weakref — Schwache Referenzen

Quellcode: Lib/weakref.py


Das Modul weakref ermöglicht dem Python-Programmierer die Erstellung von schwachen Referenzen auf Objekte.

Im Folgenden bedeutet der Begriff Referent das Objekt, auf das von einer schwachen Referenz verwiesen wird.

Eine schwache Referenz auf ein Objekt reicht nicht aus, um das Objekt am Leben zu halten: Wenn die einzigen verbleibenden Referenzen auf einen Referenten schwache Referenzen sind, ist die Garbage Collection frei, den Referenten zu zerstören und seinen Speicher für etwas anderes wiederzuverwenden. Solange das Objekt jedoch nicht tatsächlich zerstört wird, kann die schwache Referenz das Objekt zurückgeben, auch wenn keine starken Referenzen darauf existieren.

Ein Hauptanwendungsfall für schwache Referenzen ist die Implementierung von Caches oder Abbildungen, die große Objekte enthalten, bei denen es erwünscht ist, dass ein großes Objekt nicht allein deshalb am Leben erhalten wird, weil es in einem Cache oder einer Abbildung vorkommt.

Wenn Sie beispielsweise eine Reihe von großen Binärbildobjekten haben, möchten Sie jedem einen Namen zuordnen. Wenn Sie ein Python-Dictionary verwenden würden, um Namen auf Bilder oder Bilder auf Namen abzubilden, würden die Bildobjekte nur deshalb am Leben bleiben, weil sie als Werte oder Schlüssel in den Dictionaries vorkommen. Die vom Modul weakref bereitgestellten Klassen WeakKeyDictionary und WeakValueDictionary sind eine Alternative, die schwache Referenzen verwenden, um Abbildungen zu konstruieren, die Objekte nicht allein deshalb am Leben halten, weil sie in den Abbildungsobjekten vorkommen. Wenn beispielsweise ein Bildobjekt ein Wert in einem WeakValueDictionary ist, dann kann die Garbage Collection das Objekt wiederverwerten, wenn die letzten verbleibenden Referenzen auf dieses Bildobjekt die von schwachen Abbildungen gehaltenen schwachen Referenzen sind, und seine entsprechenden Einträge in schwachen Abbildungen werden einfach gelöscht.

WeakKeyDictionary und WeakValueDictionary verwenden schwache Referenzen in ihrer Implementierung, indem sie Callback-Funktionen für die schwachen Referenzen einrichten, die die schwachen Dictionaries benachrichtigen, wenn ein Schlüssel oder Wert von der Garbage Collection wiederhergestellt wurde. WeakSet implementiert die set-Schnittstelle, speichert aber schwache Referenzen auf seine Elemente, genau wie ein WeakKeyDictionary.

finalize bietet eine einfache Möglichkeit, eine Bereinigungsfunktion zu registrieren, die aufgerufen wird, wenn ein Objekt von der Garbage Collection gesammelt wird. Dies ist einfacher zu verwenden als die Einrichtung einer Callback-Funktion auf einer rohen schwachen Referenz, da das Modul automatisch sicherstellt, dass der Finalizer am Leben bleibt, bis das Objekt gesammelt wird.

Die meisten Programme sollten feststellen, dass die Verwendung eines dieser schwachen Containertypen oder finalize alles ist, was sie benötigen – es ist normalerweise nicht notwendig, eigene schwache Referenzen direkt zu erstellen. Die Low-Level-Mechanismen werden vom Modul weakref für fortgeschrittene Anwendungen bereitgestellt.

Nicht alle Objekte können schwach referenziert werden. Objekte, die schwache Referenzen unterstützen, umfassen Klasseninstanzen, in Python geschriebene Funktionen (aber nicht in C), Instanzmethoden, Sets, Frozensets, einige Dateiobjekte, Generatoren, Typobjekte, Sockets, Arrays, Deques, reguläre Ausdrucksmusterobjekte und Codeobjekte.

Geändert in Version 3.2: Unterstützung für thread.lock, threading.Lock und Codeobjekte hinzugefügt.

Mehrere eingebaute Typen wie list und dict unterstützen schwache Referenzen nicht direkt, können aber durch Unterklassifizierung Unterstützung hinzufügen.

class Dict(dict):
    pass

obj = Dict(red=1, green=2, blue=3)   # this object is weak referenceable

CPython Implementierungsdetail: Andere eingebaute Typen wie tuple und int unterstützen keine schwachen Referenzen, auch nicht beim Unterklassifizieren.

Erweiterungstypen können leicht so angepasst werden, dass sie schwache Referenzen unterstützen; siehe Unterstützung für schwache Referenzen.

Wenn für einen bestimmten Typ __slots__ definiert sind, ist die Unterstützung für schwache Referenzen deaktiviert, es sei denn, ein String '__weakref__' ist ebenfalls in der Sequenz von Strings in der __slots__-Deklaration enthalten. Weitere Einzelheiten finden Sie in der Dokumentation zu __slots__.

class weakref.ref(object[, callback])

Gibt eine schwache Referenz auf object zurück. Das ursprüngliche Objekt kann durch Aufrufen des Referenzobjekts abgerufen werden, wenn der Referent noch lebendig ist; wenn der Referent nicht mehr lebendig ist, führt der Aufruf des Referenzobjekts dazu, dass None zurückgegeben wird. Wenn callback angegeben ist und nicht None ist und das zurückgegebene schwache Referenzobjekt noch lebendig ist, wird der Callback aufgerufen, wenn das Objekt kurz vor der Finalisierung steht; das schwache Referenzobjekt wird als einziger Parameter an den Callback übergeben; der Referent ist dann nicht mehr verfügbar.

Es ist zulässig, viele schwache Referenzen für dasselbe Objekt zu erstellen. Die für jede schwache Referenz registrierten Callbacks werden vom zuletzt registrierten Callback bis zum ältesten registrierten Callback aufgerufen.

Von den Callbacks ausgelöste Ausnahmen werden in der Standardfehlerausgabe vermerkt, können aber nicht weitergegeben werden; sie werden genau auf die gleiche Weise behandelt wie Ausnahmen, die von der __del__()-Methode eines Objekts ausgelöst werden.

Schwache Referenzen sind hashbar, wenn das object hashbar ist. Sie behalten ihren Hashwert auch nach der Löschung des object. Wenn hash() das erste Mal nur nach der Löschung des object aufgerufen wird, löst der Aufruf eine TypeError aus.

Schwache Referenzen unterstützen Gleichheitstests, aber keine Ordnungsrelationen. Wenn die Referenten noch lebendig sind, haben zwei Referenzen die gleiche Gleichheitsbeziehung wie ihre Referenten (unabhängig vom callback). Wenn einer der Referenten gelöscht wurde, sind die Referenzen nur dann gleich, wenn die Referenzobjekte dasselbe Objekt sind.

Dies ist ein unterklassifizierbarer Typ und keine Factory-Funktion.

__callback__

Dieses schreibgeschützte Attribut gibt den aktuell dem schwachen Referenzobjekt zugeordneten Callback zurück. Wenn kein Callback vorhanden ist oder der Referent des schwachen Referenzobjekts nicht mehr lebendig ist, hat dieses Attribut den Wert None.

Geändert in Version 3.4: Das Attribut __callback__ wurde hinzugefügt.

weakref.proxy(object[, callback])

Gibt einen Proxy für object zurück, der eine schwache Referenz verwendet. Dies ermöglicht die Verwendung des Proxys in den meisten Kontexten, anstatt die explizite Dereferenzierung zu verlangen, die bei schwachen Referenzobjekten erforderlich ist. Das zurückgegebene Objekt hat entweder den Typ ProxyType oder CallableProxyType, je nachdem, ob object aufrufbar ist. Proxy-Objekte sind unabhängig vom Referenten nicht hashbar; dies vermeidet eine Reihe von Problemen im Zusammenhang mit ihrer grundlegend veränderlichen Natur und verhindert ihre Verwendung als Dictionary-Schlüssel. callback ist dasselbe wie der Parameter mit demselben Namen für die Funktion ref().

Der Zugriff auf ein Attribut des Proxy-Objekts, nachdem der Referent von der Garbage Collection gesammelt wurde, löst eine ReferenceError aus.

Geändert in Version 3.8: Unterstützung für Operatoren auf Proxy-Objekten wurde um die Matrixmultiplikationsoperatoren @ und @= erweitert.

weakref.getweakrefcount(object)

Gibt die Anzahl der schwachen Referenzen und Proxys zurück, die auf object verweisen.

weakref.getweakrefs(object)

Gibt eine Liste aller schwachen Referenz- und Proxy-Objekte zurück, die auf object verweisen.

class weakref.WeakKeyDictionary([dict])

Mapping-Klasse, die Schlüssel schwach referenziert. Einträge im Dictionary werden verworfen, wenn keine starke Referenz mehr auf den Schlüssel existiert. Dies kann verwendet werden, um zusätzliche Daten mit einem Objekt zu verknüpfen, das von anderen Teilen einer Anwendung besessen wird, ohne Attribute zu diesen Objekten hinzuzufügen. Dies kann besonders nützlich sein bei Objekten, die Attributzugriffe überschreiben.

Beachten Sie, dass beim Einfügen eines Schlüssels mit gleichem Wert wie ein vorhandener Schlüssel (aber nicht gleicher Identität) in das Dictionary der Wert ersetzt wird, aber nicht der vorhandene Schlüssel. Aus diesem Grund wird beim Löschen der Referenz auf den ursprünglichen Schlüssel auch der Eintrag im Dictionary gelöscht.

>>> class T(str): pass
...
>>> k1, k2 = T(), T()
>>> d = weakref.WeakKeyDictionary()
>>> d[k1] = 1   # d = {k1: 1}
>>> d[k2] = 2   # d = {k1: 2}
>>> del k1      # d = {}

Ein Workaround wäre, den Schlüssel vor der Neuzuweisung zu entfernen.

>>> class T(str): pass
...
>>> k1, k2 = T(), T()
>>> d = weakref.WeakKeyDictionary()
>>> d[k1] = 1   # d = {k1: 1}
>>> del d[k1]
>>> d[k2] = 2   # d = {k2: 2}
>>> del k1      # d = {k2: 2}

Geändert in Version 3.9: Unterstützung für die Operatoren | und |= hinzugefügt, wie in PEP 584 spezifiziert.

WeakKeyDictionary-Objekte verfügen über eine zusätzliche Methode, die die internen Referenzen direkt offenlegt. Es kann nicht garantiert werden, dass die Referenzen zum Zeitpunkt ihrer Verwendung "lebendig" sind, daher muss das Ergebnis des Aufrufs der Referenzen vor der Verwendung überprüft werden. Dies kann verwendet werden, um die Erstellung von Referenzen zu vermeiden, die den Garbage Collector dazu veranlassen würden, die Schlüssel länger als nötig am Leben zu halten.

WeakKeyDictionary.keyrefs()

Gibt ein iterierbares Objekt der schwachen Referenzen auf die Schlüssel zurück.

class weakref.WeakValueDictionary([dict])

Mapping-Klasse, die Werte schwach referenziert. Einträge im Dictionary werden verworfen, wenn keine starke Referenz mehr auf den Wert existiert.

Geändert in Version 3.9: Unterstützung für die Operatoren | und |= hinzugefügt, wie in PEP 584 spezifiziert.

WeakValueDictionary-Objekte verfügen über eine zusätzliche Methode, die die gleichen Probleme aufweist wie die Methode WeakKeyDictionary.keyrefs().

WeakValueDictionary.valuerefs()

Gibt ein iterierbares Objekt der schwachen Referenzen auf die Werte zurück.

class weakref.WeakSet([elements])

Set-Klasse, die schwache Referenzen auf ihre Elemente speichert. Ein Element wird verworfen, wenn keine starke Referenz mehr darauf existiert.

class weakref.WeakMethod(method[, callback])

Eine benutzerdefinierte ref-Unterklasse, die eine schwache Referenz auf eine gebundene Methode (d. h. eine auf einer Klasse definierte und auf einer Instanz nachgeschlagene Methode) simuliert. Da eine gebundene Methode vergänglich ist, kann eine normale schwache Referenz sie nicht festhalten. WeakMethod enthält speziellen Code, um die gebundene Methode wiederherzustellen, bis entweder das Objekt oder die ursprüngliche Funktion stirbt.

>>> class C:
...     def method(self):
...         print("method called!")
...
>>> c = C()
>>> r = weakref.ref(c.method)
>>> r()
>>> r = weakref.WeakMethod(c.method)
>>> r()
<bound method C.method of <__main__.C object at 0x7fc859830220>>
>>> r()()
method called!
>>> del c
>>> gc.collect()
0
>>> r()
>>>

callback ist dasselbe wie der Parameter mit demselben Namen für die Funktion ref().

Hinzugefügt in Version 3.4.

class weakref.finalize(obj, func, /, *args, **kwargs)

Gibt ein aufrufbares Finalizer-Objekt zurück, das aufgerufen wird, wenn obj von der Garbage Collection gesammelt wird. Im Gegensatz zu einer gewöhnlichen schwachen Referenz überlebt ein Finalizer immer, bis das Referenzobjekt gesammelt wird, was die Lebenszyklusverwaltung erheblich vereinfacht.

Ein Finalizer gilt als lebendig, bis er aufgerufen wird (entweder explizit oder bei der Garbage Collection), und danach ist er tot. Das Aufrufen eines lebendigen Finalizers gibt das Ergebnis der Auswertung von func(*arg, **kwargs) zurück, während das Aufrufen eines toten Finalizers None zurückgibt.

Von Finalizer-Callbacks während der Garbage Collection ausgelöste Ausnahmen werden in der Standardfehlerausgabe angezeigt, können aber nicht weitergegeben werden. Sie werden auf die gleiche Weise behandelt wie Ausnahmen, die von der __del__()-Methode eines Objekts oder dem Callback einer schwachen Referenz ausgelöst werden.

Beim Beenden des Programms wird jeder verbleibende lebendige Finalizer aufgerufen, es sei denn, sein atexit-Attribut wurde auf false gesetzt. Sie werden in umgekehrter Reihenfolge ihrer Erstellung aufgerufen.

Ein Finalizer ruft seinen Callback niemals während des späteren Teils der Interpreter-Beendigung auf, wenn globale Module wahrscheinlich durch None ersetzt wurden.

__call__()

Wenn self lebendig ist, wird es als tot markiert und das Ergebnis des Aufrufs von func(*args, **kwargs) zurückgegeben. Wenn self tot ist, wird None zurückgegeben.

detach()

Wenn self lebendig ist, wird es als tot markiert und das Tupel (obj, func, args, kwargs) zurückgegeben. Wenn self tot ist, wird None zurückgegeben.

peek()

Wenn self lebendig ist, wird das Tupel (obj, func, args, kwargs) zurückgegeben. Wenn self tot ist, wird None zurückgegeben.

alive

Eigenschaft, die wahr ist, wenn der Finalizer lebendig ist, sonst falsch.

atexit

Eine schreibbare boolesche Eigenschaft, die standardmäßig true ist. Beim Beenden des Programms ruft sie alle verbleibenden lebendigen Finalizer auf, für die atexit true ist. Sie werden in umgekehrter Reihenfolge ihrer Erstellung aufgerufen.

Hinweis

Es ist wichtig sicherzustellen, dass func, args und kwargs keine Referenzen auf obj besitzen, weder direkt noch indirekt, da obj sonst niemals von der Garbage Collection gesammelt wird. Insbesondere sollte func keine gebundene Methode von obj sein.

Hinzugefügt in Version 3.4.

weakref.ReferenceType

Das Typobjekt für schwache Referenzobjekte.

weakref.ProxyType

Das Typobjekt für Proxys von Objekten, die nicht aufrufbar sind.

weakref.CallableProxyType

Das Typobjekt für Proxys von aufrufbaren Objekten.

weakref.ProxyTypes

Sequenz, die alle Typobjekte für Proxys enthält. Dies kann es einfacher machen, zu testen, ob ein Objekt ein Proxy ist, ohne von der Benennung beider Proxy-Typen abhängig zu sein.

Siehe auch

PEP 205 — Weak References

Der Vorschlag und die Begründung für diese Funktion, einschließlich Links zu früheren Implementierungen und Informationen über ähnliche Funktionen in anderen Sprachen.

Objekte schwacher Referenzen

Objekte schwacher Referenzen haben keine Methoden und keine Attribute außer ref.__callback__. Ein Objekt schwacher Referenz ermöglicht das Abrufen des Referenten, falls er noch existiert, durch Aufrufen desselben.

>>> import weakref
>>> class Object:
...     pass
...
>>> o = Object()
>>> r = weakref.ref(o)
>>> o2 = r()
>>> o is o2
True

Wenn der Referent nicht mehr existiert, gibt der Aufruf des Referenzobjekts None zurück.

>>> del o, o2
>>> print(r())
None

Der Test, ob ein Objekt schwacher Referenzen noch lebendig ist, sollte mit dem Ausdruck ref() is not None erfolgen. Normalerweise sollte Anwendungscode, der ein Referenzobjekt verwenden muss, diesem Muster folgen:

# r is a weak reference object
o = r()
if o is None:
    # referent has been garbage collected
    print("Object has been deallocated; can't frobnicate.")
else:
    print("Object is still live!")
    o.do_something_useful()

Ein separater Test auf "Lebendigkeit" erzeugt Race Conditions in Multithread-Anwendungen; ein anderer Thread kann eine schwache Referenz ungültig machen, bevor die schwache Referenz aufgerufen wird; das obige Idiom ist sowohl in Multithread-Anwendungen als auch in Single-Thread-Anwendungen sicher.

Spezialisierte Versionen von ref-Objekten können durch Unterklassifizierung erstellt werden. Dies wird in der Implementierung des WeakValueDictionary verwendet, um den Speicheraufwand für jeden Eintrag in der Abbildung zu reduzieren. Dies kann am nützlichsten sein, um zusätzliche Informationen mit einer Referenz zu verknüpfen, könnte aber auch verwendet werden, um zusätzliche Verarbeitung beim Abrufen des Referenten einzufügen.

Dieses Beispiel zeigt, wie eine Unterklasse von ref verwendet werden kann, um zusätzliche Informationen über ein Objekt zu speichern und den Wert zu beeinflussen, der zurückgegeben wird, wenn auf den Referenten zugegriffen wird.

import weakref

class ExtendedRef(weakref.ref):
    def __init__(self, ob, callback=None, /, **annotations):
        super().__init__(ob, callback)
        self.__counter = 0
        for k, v in annotations.items():
            setattr(self, k, v)

    def __call__(self):
        """Return a pair containing the referent and the number of
        times the reference has been called.
        """
        ob = super().__call__()
        if ob is not None:
            self.__counter += 1
            ob = (ob, self.__counter)
        return ob

Beispiel

Dieses einfache Beispiel zeigt, wie eine Anwendung Objekt-IDs verwenden kann, um zuvor gesehene Objekte abzurufen. Die IDs der Objekte können dann in anderen Datenstrukturen verwendet werden, ohne dass die Objekte am Leben bleiben müssen, aber die Objekte können immer noch anhand ihrer ID abgerufen werden, wenn sie es tun.

import weakref

_id2obj_dict = weakref.WeakValueDictionary()

def remember(obj):
    oid = id(obj)
    _id2obj_dict[oid] = obj
    return oid

def id2obj(oid):
    return _id2obj_dict[oid]

Finalizer-Objekte

Der Hauptvorteil der Verwendung von finalize besteht darin, dass es einfach ist, einen Callback zu registrieren, ohne das zurückgegebene Finalizer-Objekt erhalten zu müssen. Zum Beispiel:

>>> import weakref
>>> class Object:
...     pass
...
>>> kenny = Object()
>>> weakref.finalize(kenny, print, "You killed Kenny!")
<finalize object at ...; for 'Object' at ...>
>>> del kenny
You killed Kenny!

Der Finalizer kann auch direkt aufgerufen werden. Der Finalizer ruft jedoch den Callback höchstens einmal auf.

>>> def callback(x, y, z):
...     print("CALLBACK")
...     return x + y + z
...
>>> obj = Object()
>>> f = weakref.finalize(obj, callback, 1, 2, z=3)
>>> assert f.alive
>>> assert f() == 6
CALLBACK
>>> assert not f.alive
>>> f()                     # callback not called because finalizer dead
>>> del obj                 # callback not called because finalizer dead

Sie können einen Finalizer mit seiner detach()-Methode deregistrieren. Dies tötet den Finalizer und gibt die Argumente zurück, die dem Konstruktor beim Erstellen übergeben wurden.

>>> obj = Object()
>>> f = weakref.finalize(obj, callback, 1, 2, z=3)
>>> f.detach()
(<...Object object ...>, <function callback ...>, (1, 2), {'z': 3})
>>> newobj, func, args, kwargs = _
>>> assert not f.alive
>>> assert newobj is obj
>>> assert func(*args, **kwargs) == 6
CALLBACK

Sofern Sie das Attribut atexit nicht auf False setzen, wird ein Finalizer beim Beenden des Programms aufgerufen, wenn er noch lebendig ist. Zum Beispiel:

>>> obj = Object()
>>> weakref.finalize(obj, print, "obj dead or exiting")
<finalize object at ...; for 'Object' at ...>
>>> exit()
obj dead or exiting

Vergleich von Finalizern mit __del__()-Methoden

Nehmen wir an, wir möchten eine Klasse erstellen, deren Instanzen temporäre Verzeichnisse darstellen. Die Verzeichnisse sollen mit ihrem Inhalt gelöscht werden, sobald eines der folgenden Ereignisse eintritt:

  • das Objekt wird vom Garbage Collector eingesammelt,

  • die remove()-Methode des Objekts wird aufgerufen, oder

  • das Programm wird beendet.

Wir könnten versuchen, die Klasse mithilfe einer __del__()-Methode wie folgt zu implementieren:

class TempDir:
    def __init__(self):
        self.name = tempfile.mkdtemp()

    def remove(self):
        if self.name is not None:
            shutil.rmtree(self.name)
            self.name = None

    @property
    def removed(self):
        return self.name is None

    def __del__(self):
        self.remove()

Ab Python 3.4 verhindern __del__()-Methoden nicht mehr, dass Referenzzyklen vom Garbage Collector eingesammelt werden, und Modul-Globals werden während des Interpreter-Shutdowns nicht mehr gezwungen, zu None zu werden. Dieser Code sollte also auf CPython ohne Probleme funktionieren.

Die Handhabung von __del__()-Methoden ist jedoch bekanntermaßen implementierungsspezifisch, da sie von internen Details der Garbage Collector-Implementierung des Interpreters abhängt.

Eine robustere Alternative besteht darin, einen Finalizer zu definieren, der nur auf die spezifischen Funktionen und Objekte verweist, die er benötigt, anstatt Zugriff auf den vollständigen Zustand des Objekts zu haben.

class TempDir:
    def __init__(self):
        self.name = tempfile.mkdtemp()
        self._finalizer = weakref.finalize(self, shutil.rmtree, self.name)

    def remove(self):
        self._finalizer()

    @property
    def removed(self):
        return not self._finalizer.alive

So definiert erhält unser Finalizer nur einen Verweis auf die Details, die er zur ordnungsgemäßen Bereinigung des Verzeichnisses benötigt. Wenn das Objekt nie vom Garbage Collector eingesammelt wird, wird der Finalizer beim Beenden trotzdem aufgerufen.

Der weitere Vorteil von schwachen Referenz-basierten Finalizern ist, dass sie verwendet werden können, um Finalizer für Klassen zu registrieren, deren Definition von einer dritten Partei gesteuert wird, z. B. um Code auszuführen, wenn ein Modul entladen wird.

import weakref, sys
def unloading_module():
    # implicit reference to the module globals from the function body
weakref.finalize(sys.modules[__name__], unloading_module)

Hinweis

Wenn Sie ein Finalizer-Objekt in einem daimonischen Thread erstellen, kurz bevor das Programm beendet wird, besteht die Möglichkeit, dass der Finalizer beim Beenden nicht aufgerufen wird. In einem daimonischen Thread garantieren jedoch atexit.register(), try: ... finally: ... und with: ... ebenfalls nicht, dass eine Bereinigung erfolgt.