1180 Stimmen

Verwendung von __slots__?

Was ist der Zweck von __slots__ in Python - vor allem im Hinblick darauf, wann ich es verwenden möchte und wann nicht?

14voto

Demolishun Punkte 1552

Slots sind sehr nützlich für Bibliotheksaufrufe, um das "named method dispatch" bei Funktionsaufrufen zu vermeiden. Dies wird in der SWIG Dokumentation . Für Hochleistungsbibliotheken, die den Funktions-Overhead für häufig aufgerufene Funktionen reduzieren wollen, ist die Verwendung von Slots viel schneller.

Das hat vielleicht nicht direkt etwas mit der Frage des Auftraggebers zu tun. Es bezieht sich eher auf den Aufbau von Erweiterungen als auf die Verwendung der Steckplätze Syntax für ein Objekt. Aber es hilft, das Bild für die Verwendung von Slots und einige der dahinter stehenden Überlegungen zu vervollständigen.

12voto

N Randhawa Punkte 7493

Ein sehr einfaches Beispiel für __slot__ Attribut.

Problem: Ohne __slots__

Wenn ich keine __slot__ Attribut in meiner Klasse kann ich neue Attribute zu meinen Objekten hinzufügen.

class Test:
    pass

obj1=Test()
obj2=Test()

print(obj1.__dict__)  #--> {}
obj1.x=12
print(obj1.__dict__)  # --> {'x': 12}
obj1.y=20
print(obj1.__dict__)  # --> {'x': 12, 'y': 20}

obj2.x=99
print(obj2.__dict__)  # --> {'x': 99}

Im obigen Beispiel sehen Sie, dass obj1 y obj2 haben ihre eigene x y y Attribute und Python hat auch eine dict Attribut für jedes Objekt ( obj1 y obj2 ).

Angenommen, meine Klasse Test Tausende solcher Objekte besitzt? Ein zusätzliches Attribut erstellen dict für jedes Objekt wird viel Overhead (Speicher, Rechenleistung usw.) in meinem Code verursachen.

Lösung: Mit __slots__

Im folgenden Beispiel wird meine Klasse Test enthält __slots__ Attribut. Jetzt kann ich keine neuen Attribute zu meinen Objekten hinzufügen (außer Attribut x ) und Python erstellt keine dict Attribut nicht mehr. Damit entfällt der Overhead für jedes Objekt, der bei vielen Objekten erheblich sein kann.

class Test:
    __slots__=("x")

obj1=Test()
obj2=Test()
obj1.x=12
print(obj1.x)  # --> 12
obj2.x=99
print(obj2.x)  # --> 99

obj1.y=28
print(obj1.y)  # --> AttributeError: 'Test' object has no attribute 'y'

11voto

Dmitry Rubanovich Punkte 2383

Ein Attribut einer Klasseninstanz hat 3 Eigenschaften: die Instanz, den Namen des Attributs und den Wert des Attributs.

Unter regelmäßiger Zugriff auf Attribute Die Instanz fungiert als Wörterbuch, und der Name des Attributs fungiert als Schlüssel in diesem Wörterbuch, das nach Werten sucht.

Instanz(Attribut) --> Wert

Unter __slots__ Zugang Der Name des Attributs fungiert als Wörterbuch, und die Instanz fungiert als Schlüssel im Wörterbuch für die Suche nach Werten.

Attribut(Instanz) --> Wert

Unter Fliegengewichtsmuster Bei der Suche nach der Instanz fungiert der Name des Attributs als Wörterbuch und der Wert als Schlüssel in diesem Wörterbuch.

Attribut(Wert) --> Instanz

6voto

Beginnend mit Python 3.9 kann eine dict kann verwendet werden, um Beschreibungen zu Attributen hinzuzufügen über __slots__ . None kann für Attribute ohne Beschreibung verwendet werden, und private Variablen erscheinen nicht, auch wenn eine Beschreibung angegeben ist.

class Person:

    __slots__ = {
        "birthday":
            "A datetime.date object representing the person's birthday.",
        "name":
            "The first and last name.",
        "public_variable":
            None,
        "_private_variable":
            "Description",
    }

help(Person)
"""
Help on class Person in module __main__:

class Person(builtins.object)
 |  Data descriptors defined here:
 |
 |  birthday
 |      A datetime.date object representing the person's birthday.
 |
 |  name
 |      The first and last name.
 |
 |  public_variable
"""

3voto

NeilenMarais Punkte 2621

Eine weitere etwas obskure Verwendung von __slots__ ist das Hinzufügen von Attributen zu einem Objekt-Proxy aus dem Paket ProxyTypes, das früher Teil des PEAK-Projekts war. Sein ObjectWrapper ermöglicht es Ihnen, ein anderes Objekt zu vertreten, aber alle Interaktionen mit dem vertretenen Objekt abzufangen. Es wird nicht sehr häufig verwendet (und es gibt keine Unterstützung für Python 3), aber wir haben es verwendet, um einen thread-sicheren blockierenden Wrapper um eine asynchrone Implementierung auf der Basis von Tornado zu implementieren, der alle Zugriffe auf das Proxy-Objekt durch den ioloop weiterleitet, wobei thread-sichere concurrent.Future Objekte zu synchronisieren und Ergebnisse zurückzugeben.

Standardmäßig wird jeder Attributzugriff auf das Proxy-Objekt das Ergebnis des Proxy-Objekts liefern. Wenn Sie ein Attribut zum Proxy-Objekt hinzufügen müssen, __slots__ verwendet werden können.

from peak.util.proxies import ObjectWrapper

class Original(object):
    def __init__(self):
        self.name = 'The Original'

class ProxyOriginal(ObjectWrapper):

    __slots__ = ['proxy_name']

    def __init__(self, subject, proxy_name):
        # proxy_info attributed added directly to the
        # Original instance, not the ProxyOriginal instance
        self.proxy_info = 'You are proxied by {}'.format(proxy_name)

        # proxy_name added to ProxyOriginal instance, since it is
        # defined in __slots__
        self.proxy_name = proxy_name

        super(ProxyOriginal, self).__init__(subject)

if __name__ == "__main__":
    original = Original()
    proxy = ProxyOriginal(original, 'Proxy Overlord')

    # Both statements print "The Original"
    print "original.name: ", original.name
    print "proxy.name: ", proxy.name

    # Both statements below print 
    # "You are proxied by Proxy Overlord", since the ProxyOriginal
    # __init__ sets it to the original object 
    print "original.proxy_info: ", original.proxy_info
    print "proxy.proxy_info: ", proxy.proxy_info

    # prints "Proxy Overlord"
    print "proxy.proxy_name: ", proxy.proxy_name
    # Raises AttributeError since proxy_name is only set on 
    # the proxy object
    print "original.proxy_name: ", proxy.proxy_name

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X