weakref
— Svaga referenser¶
Källkod: Lib/weakref.py
Modulen weakref
gör det möjligt för Python-programmerare att skapa svaga referenser till objekt.
I det följande betyder termen referent det objekt som refereras till med en svag referens.
En svag referens till ett objekt räcker inte för att hålla objektet vid liv: när de enda återstående referenserna till en referent är svaga referenser, kan garbage collection fritt förstöra referenten och återanvända dess minne till något annat. Fram till dess att objektet faktiskt förstörs kan dock den svaga referensen returnera objektet även om det inte finns några starka referenser till det.
En primär användning av svaga referenser är att implementera cacheminnen eller mappningar som innehåller stora objekt, där det är önskvärt att ett stort objekt inte hålls vid liv enbart för att det förekommer i ett cacheminne eller en mappning.
Om du till exempel har ett antal stora binära bildobjekt kanske du vill associera ett namn med varje objekt. Om du använde en Python-ordbok för att mappa namn till bilder, eller bilder till namn, skulle bildobjekten förbli levande bara för att de dök upp som värden eller nycklar i ordböckerna. Klasserna WeakKeyDictionary
och WeakValueDictionary
som tillhandahålls av modulen weakref
är ett alternativ som använder svaga referenser för att konstruera mappningar som inte håller objekt vid liv enbart för att de förekommer i mappningsobjekten. Om t.ex. ett bildobjekt är ett värde i en WeakValueDictionary
, och när de sista kvarvarande referenserna till bildobjektet är svaga referenser i svaga mappningar, kan skräpsamlingen återta objektet och motsvarande poster i svaga mappningar raderas helt enkelt.
WeakKeyDictionary
och WeakValueDictionary
använder svaga referenser i sin implementering och skapar callback-funktioner på de svaga referenserna som meddelar de svaga ordböckerna när en nyckel eller ett värde har återvunnits av garbage collection. WeakSet
implementerar gränssnittet set
, men behåller svaga referenser till sina element, precis som en WeakKeyDictionary
gör.
finalize
ger ett enkelt sätt att registrera en rensningsfunktion som ska anropas när ett objekt samlas in. Detta är enklare att använda än att sätta upp en callback-funktion på en svag referens, eftersom modulen automatiskt ser till att finalizer-funktionen hålls vid liv tills objektet samlas in.
De flesta program bör finna att det räcker med att använda en av dessa svaga containertyper eller finalize
- det är vanligtvis inte nödvändigt att skapa egna svaga referenser direkt. Maskineriet på låg nivå exponeras av modulen weakref
till förmån för avancerade användningsområden.
Det är inte alla objekt som kan refereras svagt. Objekt som stöder svaga referenser inkluderar klassinstanser, funktioner skrivna i Python (men inte i C), instansmetoder, set, frozensets, vissa filobjekt, generatorer, typobjekt, sockets, matriser, deques, mönsterobjekt för reguljära uttryck och kodobjekt.
Ändrad i version 3.2: Lagt till stöd för thread.lock, threading.Lock och kodobjekt.
Flera inbyggda typer som list
och dict
har inte direkt stöd för svaga referenser men kan lägga till stöd genom underklassning:
klass Dict(dict):
pass
obj = Dict(röd=1, grön=2, blå=3) # detta objekt är svagt refererbart
Tilläggstyper kan enkelt göras för att stödja svaga referenser; se Svagt referensstöd.
När __slots__
definieras för en viss typ inaktiveras stödet för svaga referenser om inte en sträng av typen '__weakref__'
också finns i sekvensen av strängar i __slots__
-deklarationen. Se dokumentation för __slots__ för detaljer.
- class weakref.ref(object[, callback])¶
Returnerar en svag referens till object. Det ursprungliga objektet kan hämtas genom att anropa referensobjektet om referenten fortfarande är vid liv; om referenten inte längre är vid liv kommer anrop av referensobjektet att leda till att
None
returneras. Om callback anges och inteNone
, och det returnerade weakref-objektet fortfarande är vid liv, kommer callbacken att anropas när objektet är på väg att slutföras; det svaga referensobjektet kommer att skickas som den enda parametern till callbacken; referenten kommer inte längre att vara tillgänglig.Det är tillåtet att konstruera många svaga referenser för samma objekt. Callbacks som registrerats för varje svag referens kommer att anropas från den senast registrerade callbacken till den äldsta registrerade callbacken.
Undantag som orsakas av återuppringningen noteras i standardfelutmatningen, men kan inte spridas; de hanteras på exakt samma sätt som undantag som orsakas av ett objekts
__del__()
-metod.Svaga referenser är hashable om objektet är hashbart. De behåller sitt hashvärde även efter att objektet har tagits bort. Om
hash()
anropas första gången först efter att objektet har tagits bort, kommer anropet att ge upphov tillTypeError
.Svaga referenser stöder tester för jämlikhet, men inte för ordning. Om referenterna fortfarande är vid liv har två referenser samma jämlikhetsrelation som sina referenter (oavsett callback). Om någon av referenterna har tagits bort är referenserna jämlika endast om referensobjekten är samma objekt.
Detta är en underklassbar typ snarare än en fabriksfunktion.
- __callback__¶
Detta skrivskyddade attribut returnerar den återuppringning som för närvarande är associerad med weakref. Om det inte finns någon återkallelse eller om referenten till weakref inte längre lever kommer detta attribut att ha värdet
None
.
Ändrad i version 3.4: Lagt till attributet
__callback__
.
- weakref.proxy(object[, callback])¶
Returnerar en proxy till object som använder en svag referens. Detta stödjer användning av proxyn i de flesta sammanhang istället för att kräva den explicita dereferencing som används med svaga referensobjekt. Det returnerade objektet kommer att ha en typ av antingen
ProxyType
ellerCallableProxyType
, beroende på om object är anropsbart. Proxy-objekt är inte hashable oavsett referent; detta undviker ett antal problem relaterade till deras fundamentalt föränderliga natur, och förhindrar deras användning som ordboksnycklar. callback är detsamma som parametern med samma namn till funktionenref()
.Åtkomst till ett attribut för proxyobjektet efter att referenten har samlats in ger upphov till
ReferenceError
.Ändrad i version 3.8: Utökat operatorsstöd för proxyobjekt till att omfatta matrismultiplikationsoperatorerna
@
och@=
.
- weakref.getweakrefcount(object)¶
Returnera antalet svaga referenser och proxies som refererar till objekt.
- weakref.getweakrefs(object)¶
Returnerar en lista över alla svaga referens- och proxyobjekt som refererar till object.
- class weakref.WeakKeyDictionary([dict])¶
Mappningsklass som refererar svagt till nycklar. Poster i ordlistan kommer att kasseras när det inte längre finns någon stark referens till nyckeln. Detta kan användas för att associera ytterligare data med ett objekt som ägs av andra delar av en applikation utan att lägga till attribut till dessa objekt. Detta kan vara särskilt användbart med objekt som åsidosätter attributåtkomst.
Observera att när en nyckel med samma värde som en befintlig nyckel (men inte samma identitet) infogas i ordlistan ersätter den värdet men inte den befintliga nyckeln. När referensen till den ursprungliga nyckeln raderas, raderas därför även posten i ordlistan:
>>> 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 = {}
En lösning skulle vara att ta bort nyckeln före omplaceringen:
>>> 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}
Ändrad i version 3.9: Lagt till stöd för operatorerna
|
och|=
, enligt specifikation i PEP 584.
WeakKeyDictionary
-objekt har en extra metod som exponerar de interna referenserna direkt. Det är inte säkert att referenserna är ”live” när de används, så resultatet av att anropa referenserna måste kontrolleras innan de används. Detta kan användas för att undvika att skapa referenser som gör att garbage collector behåller nycklarna längre än nödvändigt.
- WeakKeyDictionary.keyrefs()¶
Returnerar en iterabel av de svaga referenserna till nycklarna.
- class weakref.WeakValueDictionary([dict])¶
Mappningsklass som refererar svagt till värden. Poster i ordlistan kommer att kasseras när det inte längre finns någon stark referens till värdet.
Ändrad i version 3.9: Lagt till stöd för operatorerna
|
och|=
, enligt specifikation i PEP 584.
WeakValueDictionary
-objekt har en ytterligare metod som har samma problem som metoden WeakKeyDictionary.keyrefs()
.
- WeakValueDictionary.valuerefs()¶
Returnerar en iterabel med svaga referenser till värdena.
- class weakref.WeakSet([elements])¶
Set-klass som behåller svaga referenser till sina element. Ett element kasseras när det inte längre finns någon stark referens till det.
- class weakref.WeakMethod(method[, callback])¶
En anpassad
ref
-underklass som simulerar en svag referens till en bunden metod (dvs. en metod som definieras i en klass och söks upp i en instans). Eftersom en bunden metod är flyktig kan en vanlig svag referens inte hålla fast vid den.WeakMethod
har specialkod för att återskapa den bundna metoden tills antingen objektet eller den ursprungliga funktionen dör:>>> 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 är samma som parametern med samma namn till funktionen
ref()
.Tillagd i version 3.4.
- class weakref.finalize(obj, func, /, *args, **kwargs)¶
Returnerar ett anropbart finalizer-objekt som kommer att anropas när obj samlas in. Till skillnad från en vanlig svag referens kommer en finalizer alltid att överleva tills referensobjektet samlas in, vilket förenklar livscykelhanteringen avsevärt.
En finalizer anses vara alive tills den anropas (antingen explicit eller vid garbage collection), och efter det är den dead. Anrop av en levande finalizer returnerar resultatet av utvärderingen av
func(*arg, **kwargs)
, medan anrop av en död finalizer returnerarNone
.Undantag som orsakas av finalizer callbacks under garbage collection visas på standardfelutmatningen, men kan inte spridas vidare. De hanteras på samma sätt som undantag som orsakas av ett objekts
__del__()
-metod eller en svag referenss återkallelse.När programmet avslutas anropas varje kvarvarande live finalizer om inte dess attribut
atexit
har satts till false. De anropas i omvänd ordning efter att de skapats.En finalizer kommer aldrig att anropa sitt callback under den senare delen av interpreter shutdown när modulglobaler kan ha ersatts av
None
.- __call__()¶
Om self är levande markeras den som död och resultatet av anropet
func(*args, **kwargs)
returneras. Om self är död returnerasNone
.
- detach()¶
Om self är levande markeras den som död och tupeln
(obj, func, args, kwargs)
returneras. Om self är död returnerasNone
.
- peek()¶
Om self är vid liv returneras tupeln
(obj, func, args, kwargs)
. Om self är död returnerasNone
.
- alive¶
Egenskap som är sann om finalizer är levande, annars falsk.
- atexit¶
En skrivbar boolesk egenskap som som standard är true. När programmet avslutas anropas alla återstående live finalizers för vilka
atexit
är true. De anropas i omvänd ordning efter att de skapats.
Anteckning
Det är viktigt att se till att func, args och kwargs inte äger några referenser till obj, varken direkt eller indirekt, eftersom obj annars aldrig kommer att garbage collectas. I synnerhet bör func inte vara en bunden metod till obj.
Tillagd i version 3.4.
- weakref.ReferenceType¶
Typobjektet för objekt med svaga referenser.
- weakref.ProxyType¶
Typobjektet för proxies av objekt som inte är anropsbara.
- weakref.CallableProxyType¶
Typobjektet för proxyer av anropsbara objekt.
- weakref.ProxyTypes¶
Sekvens som innehåller alla typobjekt för proxy. Detta kan göra det enklare att testa om ett objekt är en proxy utan att vara beroende av att namnge båda proxytyperna.
Se även
- PEP 205 - Svaga referenser
Förslaget och motiveringen till den här funktionen, inklusive länkar till tidigare implementeringar och information om liknande funktioner i andra språk.
Svaga referensobjekt¶
Svaga referensobjekt har inga metoder och inga attribut förutom ref.__callback__
. Ett svagt referensobjekt gör att referenten kan erhållas, om den fortfarande finns, genom att anropa det:
>>> import weakref
>>> class Object:
... pass
...
>>> o = Object()
>>> r = weakref.ref(o)
>>> o2 = r()
>>> o is o2
True
Om referenten inte längre finns, returneras None
när referensobjektet anropas:
>>> del o, o2
>>> print(r())
None
Testning av att ett svagt referensobjekt fortfarande är aktivt bör göras med hjälp av uttrycket ref() is not None
. Normalt bör applikationskod som behöver använda ett referensobjekt följa detta mönster:
# r är ett svagt referensobjekt
o = r()
om o är None:
# referensen har blivit skräpinsamlad
print("Objektet har avallokerats; kan inte frobnisera.")
else:
print("Objektet är fortfarande levande!")
o.gör_något_nyttigt()
Att använda ett separat test för ”liveness” skapar tävlingsförhållanden i gängade applikationer; en annan tråd kan orsaka att en svag referens blir ogiltig innan den svaga referensen anropas; idiomet som visas ovan är säkert i gängade applikationer såväl som i enkeltrådade applikationer.
Specialiserade versioner av ref
-objekt kan skapas genom subklassning. Detta används i implementeringen av WeakValueDictionary
för att minska minneskostnaden för varje post i mappningen. Detta kan vara mest användbart för att associera ytterligare information med en referens, men kan också användas för att infoga ytterligare bearbetning vid anrop för att hämta referensen.
Detta exempel visar hur en subklass av ref
kan användas för att lagra ytterligare information om ett objekt och påverka det värde som returneras när referenten anropas:
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
Exempel¶
Detta enkla exempel visar hur en applikation kan använda objekt-ID:n för att hämta objekt som den har sett förut. Objektens ID:n kan sedan användas i andra datastrukturer utan att objekten tvingas leva vidare, men om de gör det kan de ändå hämtas via ID.
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-objekt¶
Den största fördelen med att använda finalize
är att det gör det enkelt att registrera en callback utan att behöva bevara det returnerade finalizer-objektet. Exempelvis
>>> 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!
Finalizer kan också anropas direkt. Finalizern kommer dock att anropa callbacken högst en gång.
>>> 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
Du kan avregistrera en finalizer med hjälp av dess detach()
-metod. Detta dödar finalizern och returnerar de argument som skickades till konstruktören när den skapades.
>>> 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
Om du inte sätter attributet atexit
till False
, kommer en finalizer att anropas när programmet avslutas om det fortfarande är vid liv. Exempelvis
>>> obj = Object()
>>> weakref.finalize(obj, print, "obj dead or exiting")
<finalize object at ...; for 'Object' at ...>
>>> exit()
obj dead or exiting
Jämförelse av finalizers med __del__()
-metoder¶
Antag att vi vill skapa en klass vars instanser representerar tillfälliga kataloger. Katalogerna ska raderas med sitt innehåll när den första av följande händelser inträffar:
objektet är skräpinsamlat,
objektets
remove()
-metod anropas, elleravslutas programmet.
Vi kan försöka implementera klassen med hjälp av en __del__()
-metod enligt följande:
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()
Från och med Python 3.4 förhindrar inte längre __del__()
-metoder att referenscykler garbage-samlas, och modulglobaler tvingas inte längre till None
under interpreter shutdown. Så den här koden bör fungera utan problem på CPython.
Hanteringen av __del__()
-metoder är dock notoriskt implementationsspecifik, eftersom den beror på interna detaljer i tolkens garbage collector-implementation.
Ett mer robust alternativ kan vara att definiera en finalizer som bara refererar till de specifika funktioner och objekt som den behöver, i stället för att ha tillgång till objektets fullständiga tillstånd:
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
Definierad på det här sättet får vår finalizer bara en referens till de detaljer den behöver för att städa upp katalogen på lämpligt sätt. Om objektet aldrig blir skräpinsamlat kommer finalizern fortfarande att anropas vid avslut.
Den andra fördelen med weakref-baserade finalizers är att de kan användas för att registrera finalizers för klasser där definitionen styrs av en tredje part, t.ex. att köra kod när en modul avlastas:
import weakref, sys
def unloading_module():
# implicit referens till modulens globaler från funktionskroppen
weakref.finalize(sys.modules[__name__], unloading_module)
Anteckning
Om du skapar ett finalizer-objekt i en daemonisk tråd precis när programmet avslutas finns det en möjlighet att finalizern inte anropas vid avslutningen. Men i en daemonisk tråd atexit.register()
, try: ... finally: ...
och with: ...
inte heller garantera att upprensning sker.