Was ist der Zweck von __slots__
in Python - vor allem im Hinblick darauf, wann ich es verwenden möchte und wann nicht?
Antworten
Zu viele Anzeigen?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.
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'
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
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
"""
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