[Bearbeiten 1: Erklären Sie die Art der verknüpften Liste und wann Schwachstellen wiederverwendet werden]
Interessanterweise ist die offizielle Dokumentation zu diesem Thema nicht aufschlussreich:
Ohne eine __weakref__
Variable für jede Instanz unterstützen definierende Klassen __slots__
keine schwachen Verweise auf ihre Instanzen. Wenn eine schwache Referenzunterstützung benötigt wird, fügen Sie __weakref__
die Zeichenfolge in der __slots__
Deklaration hinzu.
Die type
Objektdokumentation zum Thema scheint nicht allzu viel zu helfen:
Wenn die __slots__
Deklaration eines Typs einen Slot mit dem Namen enthält __weakref__
, wird dieser Slot zum schwachen Referenzlistenkopf für Instanzen des Typs, und der Versatz des Slots wird im Typ gespeichert tp_weaklistoffset
.
Schwache Referenzen bilden eine verknüpfte Liste. Der Kopf dieser Liste (der erste schwache Verweis auf ein Objekt) ist über verfügbar __weakref__
. Schwache Refs werden nach Möglichkeit wiederverwendet, sodass die Liste (keine Python-Liste!) In der Regel entweder leer ist oder ein einzelnes Element enthält.
Beispiel :
Bei der ersten Verwendung weakref.ref()
erstellen Sie eine neue schwache Referenzkette für das Zielobjekt. Der Kopf dieser Kette ist der neue Schwachpunkt und wird im Zielobjekt gespeichert __weakref__
:
>>> import weakref
>>> class A(object): pass
>>> a = A()
>>> b = weakref.ref(a)
>>> c = weakref.ref(b)
>>> print(b is c is a.__weakref__)
True
Wie wir sehen können, b
wird wiederverwendet. Wir können Python zwingen, eine neue Schwachstelle zu erstellen, indem wir beispielsweise einen Rückrufparameter hinzufügen:
>>> def callback():
>>> pass
>>> a = A()
>>> b = weakref.ref(a)
>>> c = weakref.ref(b, callback)
>>> print(b is c is a.__weakref__)
False
Nun b is a.__weakref__
und c
ist die zweite Referenz in der Kette. Auf die Referenzkette kann über Python-Code nicht direkt zugegriffen werden. Wir sehen nur das Kopfelement der Kette ( b
), aber nicht, wie die Kette weitergeht ( b
-> c
).
Dies __weakref__
gilt auch für den Kopf der internen verknüpften Liste aller schwachen Verweise auf das Objekt. Ich kann keine offizielle Dokumentation finden, in der diese Rolle kurz __weakref__
erklärt wird, daher sollte man sich wahrscheinlich nicht auf dieses Verhalten verlassen, da es sich um ein Implementierungsdetail handelt.
obj.__weakref__
erinnert sich also an die schwache Referenz,wr
die aufobj
einen Willen zeigt, der verwendet wird, um ungültig zu machen,wr
wannobj
Müll gesammelt wird?Die
__weakref__
Variable ist ein Attribut, mit dem das Objekt die schwachen Referenzen unterstützt und die schwachen Referenzen auf das Objekt beibehält.In der Python-Dokumentation wurde dies wie folgt erklärt:
Daher besteht die Pflicht schwacher Referenzen darin, die Bedingungen für ein Objekt bereitzustellen, damit unabhängig von seiner Art und seinem Umfang Müll gesammelt werden kann.
Und darüber
__slots__
können wir uns zunächst die Dokumentation ansehen, die es sehr gut erklärt:Da
__slots__
Sie nun mithilfe von den erforderlichen Speicher für Ihr Attribut steuern, wird die automatische Erstellung von__dict__
und__weakref__
für jede Instanz tatsächlich verhindert . Welches__weakref__
ist die notwendige Variable jedes Objekts, um mit schwachen Referenzen umgehen zu können.Zusätzlich zu all diesen Angaben heißt es in der Dokumentation für den
object.__slots__
Unterricht:Kurz gesagt, wir können daraus schließen, dass
__slots__
für die manuelle Verwaltung der Speicherzuordnung und da__weakref__
die Lizenz zum Akzeptieren der schwachen Referenzen für Objekte, die sich auf die Speicherung beziehen (aufgrund der Fähigkeit, Müll zu sammeln),__slots__
die__weakref__
as gesteuert wird sowie die Steuerung des__dict__
Attributs.Die Dokumentation hat Ihnen auch gezeigt, wie Sie ein Objekt erstellen können, um die schwachen Referenzen neben der Verwendung zu unterstützen
__slots__
:Hier ist ein Beispiel in Python 3.X:
>>> class Test: ... __slots__ = ['a', 'b'] ... >>> >>> import weakref >>> >>> t = Test() >>> >>> r = weakref.ref(t) Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: cannot create weak reference to 'Test' object >>> >>> class Test: ... __slots__ = ['a', 'b', '__weakref__'] ... >>> t = Test() >>> r = weakref.ref(t) >>> >>> t.__weakref__ <weakref at 0x7f735bc55d68; to 'Test' at 0x7f735bc51fc8>
In Python 2.7 wird jedoch, obwohl die Dokumentation den oben genannten Dokumenten ähnelt, das Erstellen einer schwachen Referenz aus Instanzen, die die
__weakref__
Variable in ihren__slots__
Namen nicht enthalten, nicht ausgelöstTypeError
:>>> class Test: ... __slots__ = ['a', 'b'] ... >>> t = Test() >>> >>> r = weakref.ref(t) >>> >>> r <weakref at 0x7fe49f4185d0; to 'instance' at 0x7fe4a3e75f80>
quelle
__weakref__
tatsächlich funktioniert (es enthält den schwachen Referenz-Singleton). Möchtest du das hinzufügen?__weakref__
. Ich vermute, dass es möglicherweise so trivial ist, dass sie es einfach weggelassen haben ...__weakref__
ist nur eine Art Flagge, die sagt: "Ja, ich kann schwach referenziert werden." (?)