weakref
— Referências fracas¶
Código-fonte: Lib/weakref.py
O módulo weakref
permite ao programador Python criar referências fracas para objetos.
A seguir, o termo referente significa o objeto ao qual é referido por uma referência fraca.
Uma referência fraca a um objeto não é suficiente para mantê-lo vivo: quando as únicas referências restantes a um referente são referências fracas, a coleta de lixo está livre para destruir o referente e reutilizar sua memória para outra coisa. Entretanto, até que o objeto seja realmente destruído, a referência fraca poderá retornar o objeto mesmo que não haja referências fortes a ele.
Um uso principal para referências fracas é implementar caches ou mapeamentos contendo objetos grandes, onde é desejado que um objeto grande não seja mantido ativo apenas porque aparece em um cache ou mapeamento.
Por exemplo, se você tiver vários objetos de imagem binária grandes, poderá associar um nome a cada um. Se você usasse um dicionário Python para mapear nomes para imagens, ou imagens para nomes, os objetos de imagem permaneceriam vivos apenas porque apareceriam como valores ou chaves nos dicionários. As classes WeakKeyDictionary
e WeakValueDictionary
fornecidas pelo módulo weakref
são uma alternativa, usando referências fracas para construir mapeamentos que não mantêm objetos vivos apenas porque aparecem nos objetos de mapeamento. Se, por exemplo, um objeto de imagem for um valor em um WeakValueDictionary
, então quando as últimas referências restantes a esse objeto de imagem forem as referências fracas mantidas por mapeamentos fracos, a coleta de lixo poderá recuperar o objeto e suas entradas correspondentes em mapeamentos fracos são simplesmente excluídos.
WeakKeyDictionary
e WeakValueDictionary
usam referências fracas em sua implementação, configurando funções de retorno de chamada nas referências fracas que notificam os dicionários fracos quando uma chave ou valor foi recuperado pela coleta de lixo. WeakSet
implementa a interface set
, mas mantém referências fracas aos seus elementos, assim como WeakKeyDictionary
faz.
finalize
fornece uma maneira direta de registrar uma função de limpeza a ser chamada quando um objeto é coletado como lixo. Isso é mais simples de usar do que configurar uma função de retorno de chamada em uma referência fraca não tratada, pois o módulo garante automaticamente que o finalizador permaneça ativo até que o objeto seja coletado.
A maioria dos programas deve descobrir que usar um desses tipos de contêineres fracos ou finalize
é tudo que eles precisam – geralmente não é necessário criar suas próprias referências fracas diretamente. O maquinário de baixo nível é exposto pelo módulo weakref
para benefício de usos avançados.
Not all objects can be weakly referenced; those objects which can include class instances, functions written in Python (but not in C), instance methods, sets, frozensets, some file objects, generators, type objects, sockets, arrays, deques, regular expression pattern objects, and code objects.
Alterado na versão 3.2: Adicionado suporte para thread.lock, threading.Lock e objetos código.
Vários tipos embutidos como list
e dict
não oferecem suporta diretamente a referências fracas, mas podem adicionar suporte através de subclasses:
class Dict(dict):
pass
obj = Dict(red=1, green=2, blue=3) # this object is weak referenceable
Detalhes da implementação do CPython: Outros tipos embutidos como tuple
e int
não oferecem suporte a referências fracas mesmo em subclasses.
Os tipos de extensão podem ser facilmente criados para oferecer suporte a referências fracas; veja Weak Reference Support.
Quando __slots__
são definidos para um determinado tipo, o suporte a referência fraca é desativado a menos que uma string '__weakref__'
também esteja presente na sequência de strings na declaração de __slots__
. Veja a documentação de __slots__ para detalhes.
-
class
weakref.
ref
(object[, callback])¶ Retorna uma referência fraca para object. O objeto original pode ser recuperado chamando o objeto referência se o referente ainda estiver ativo; se o referente não estiver mais ativo, chamar o objeto referência fará com que
None
seja retornado. Se callback for fornecido e não forNone
, e o objeto referência fraca retornado ainda estiver ativo, o função de retorno será chamada quando o objeto estiver prestes a ser finalizado; o objeto referência fraca será passado como único parâmetro para a função de retorno; o referente não estará mais disponível.É permitido que muitas referências fracas sejam construídas para o mesmo objeto. As funções de retorno registradas para cada referência fraca serão chamadas da função de retorno registrada mais recentemente para a função de retorno registrada mais antiga.
Exceptions raised by the callback will be noted on the standard error output, but cannot be propagated; they are handled in exactly the same way as exceptions raised from an object’s
__del__()
method.Referências fracas são hasheáveis se o object for hasheável. Elas manterão seu valor de hash mesmo depois que object for excluído. Se
hash()
for chamada pela primeira vez somente após o object ter sido excluído, a chamada vai levantarTypeError
.Referências fracas oferecem suporte a testes de igualdade, mas não de ordenação. Se os referentes ainda estiverem vivos, duas referências terão a mesma relação de igualdade que seus referentes (independentemente do callback). Se um dos referentes tiver sido excluído, as referências serão iguais somente se os objetos referência forem o mesmo objeto.
Este é um tipo do qual pode ser feita subclasse em vez de uma função de fábrica.
-
__callback__
¶ Este atributo somente leitura retorna a função de retorno atualmente associada à referência fraca. Se não houver função de retorno ou se o referente da referência fraca não estiver mais ativo, então este atributo terá o valor
None
.
Alterado na versão 3.4: Adicionado o atributo
__callback__
.-
-
weakref.
proxy
(object[, callback])¶ Return a proxy to object which uses a weak reference. This supports use of the proxy in most contexts instead of requiring the explicit dereferencing used with weak reference objects. The returned object will have a type of either
ProxyType
orCallableProxyType
, depending on whether object is callable. Proxy objects are not hashable regardless of the referent; this avoids a number of problems related to their fundamentally mutable nature, and prevent their use as dictionary keys. callback is the same as the parameter of the same name to theref()
function.Acessar um atributo do objeto intermediário depois que o referente é coletado como lixo levanta
ReferenceError
.Alterado na versão 3.8: Estendeu o suporte ao operador em objetos intermediários para incluir os operadores
@
e@=
para multiplicação de matrizes.
-
weakref.
getweakrefcount
(object)¶ Retorna o número de referências fracas e intermediários que fazem referência a object.
-
weakref.
getweakrefs
(object)¶ Retorna uma lista de todos os objetos intermediários e de referência fraca que fazem referência a object.
-
class
weakref.
WeakKeyDictionary
([dict])¶ Classe de mapeamento que faz referência fraca a chaves. Entradas no dicionário serão descartadas quando não houver mais uma referência forte à chave. Isso pode ser usado para associar dados adicionais a um objeto de propriedade de outras partes de uma aplicação sem adicionar atributos a esses objetos. Isso pode ser especialmente útil com objetos que substituem acessos de atributos.
Note que quando uma chave com valor igual a uma chave existente (mas não identidade igual) é inserida no dicionário, ela substitui o valor, mas não substitui a chave existente. Devido a isso, quando a referência à chave original é excluída, ela também exclui a entrada no dicionário:
>>> 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 = {}
Uma solução alternativa seria remover a chave antes da reatribuição:
>>> 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}
Alterado na versão 3.9: Adicionado suporte para os operadores
|
e|=
, especificados na PEP 584.
Objetos WeakKeyDictionary
têm um método adicional que expõe as referências internas diretamente. Não há garantia de que as referências estejam “ativas” no momento em que são usadas, então o resultado da chamada das referências precisa ser verificado antes de ser usado. Isso pode ser usado para evitar a criação de referências que farão com que o coletor de lixo mantenha as chaves por mais tempo do que o necessário.
-
WeakKeyDictionary.
keyrefs
()¶ Retorna um iterável das referências fracas às chaves.
-
class
weakref.
WeakValueDictionary
([dict])¶ Classe de mapeamento que faz referência fraca a valores. Entradas no dicionário serão descartadas quando nenhuma referência forte ao valor existir mais.
Alterado na versão 3.9: Adicionado suporte para operadores
|
e|=
, conforme especificado na PEP 584.
WeakValueDictionary
objects have an additional method that has the
same issues as the keyrefs()
method of WeakKeyDictionary
objects.
-
WeakValueDictionary.
valuerefs
()¶ Retorna um iterável das referências fracas aos valores.
-
class
weakref.
WeakSet
([elements])¶ Define a classe que mantém referências fracas para seus elementos. Um elemento será descartado quando nenhuma referência forte a ele existir mais.
-
class
weakref.
WeakMethod
(method)¶ Uma subclasse personalizada de
ref
que simula uma referência fraca a um método vinculado (ou seja, um método definido em uma classe e pesquisado em uma instância). Como um método vinculado é efêmero, uma referência fraca padrão não pode mantê-lo.WeakMethod
tem um código especial para recriar o método vinculado até que o objeto ou a função original morra:>>> 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() >>>
Novo na versão 3.4.
-
class
weakref.
finalize
(obj, func, /, *args, **kwargs)¶ Retorna um objeto finalizador chamável que será chamado quando obj for coletado como lixo. Diferentemente de uma referência fraca comum, um finalizador sempre sobreviverá até que o objeto referência seja coletado, simplificando muito o gerenciamento do ciclo de vida.
Um finalizador é considerado alive (vivo) até ser chamado (explicitamente ou na coleta de lixo), e depois disso ele é dead (morto). Chamar um finalizador vivo retorna o resultado da avaliação de
func(*arg, **kwargs)
, enquanto chamar um finalizador morto retornaNone
.Exceptions raised by finalizer callbacks during garbage collection will be shown on the standard error output, but cannot be propagated. They are handled in the same way as exceptions raised from an object’s
__del__()
method or a weak reference’s callback.Quando o programa é encerrado, cada finalizador vivo restante é chamado, a menos que seu atributo
atexit
tenha sido definido como falso. Eles são chamados na ordem reversa da criação.Um finalizador nunca vai invocar sua função de retorno durante a parte posterior do desligamento do interpretador quando os globais do módulo podem ter sido substituídos por
None
.-
__call__
()¶ Se self estiver vivo, marca-o como morto e retorna o resultado da chamada
func(*args, **kwargs)
. Se self estiver morto, retornaNone
.
-
detach
()¶ Se self estiver vivo, marca-o como morto e retorna a tupla
(obj, func, args, kwargs)
. Se self estiver morto, retornaNone
.
-
peek
()¶ Se self estiver vivo, retorna a tupla
(obj, func, args, kwargs)
. Se self estiver morto, retornaNone
.
-
alive
¶ Propriedade que é verdadeiro se o finalizador estiver ativo, falsa caso contrário.
-
atexit
¶ Uma propriedade booleana gravável que por padrão é verdadeiro. Quando o programa sai, ele chama todos os finalizadores vivos restantes para os quais
atexit
é verdadeiro. Eles são chamados na ordem reversa da criação.
Nota
É importante garantir que func, args e kwargs não possuam nenhuma referência a obj, direta ou indiretamente, pois, caso contrário, obj nunca será coletado como lixo. Em particular, func não deve ser um método vinculado de obj.
Novo na versão 3.4.
-
-
weakref.
ReferenceType
¶ O objeto tipo para objetos referências fracas.
-
weakref.
ProxyType
¶ O tipo de objeto para intermediários de objetos que não são chamáveis.
-
weakref.
CallableProxyType
¶ O objeto de tipo para intermediários de objetos chamáveis.
-
weakref.
ProxyTypes
¶ Sequência contendo todos os objetos de tipo para intermediários. Isso pode tornar mais simples testar se um objeto é um intermediário sem depender da nomeação de ambos os tipos de intermediário.
Ver também
- PEP 205 - Weak References
A proposta e a justificativa para esse recurso, incluindo links para implementações anteriores e informações sobre recursos semelhantes em outras linguagens.
Objetos referência fraca¶
Objetos referência fraca não têm métodos nem atributos além de ref.__callback__
. Um objeto referência fraca permite que o referente seja obtido, se ele ainda existir, chamando-o:
>>> import weakref
>>> class Object:
... pass
...
>>> o = Object()
>>> r = weakref.ref(o)
>>> o2 = r()
>>> o is o2
True
Se o referente não existir mais, chamar o objeto referência retornará None
:
>>> del o, o2
>>> print(r())
None
O teste de se um objeto referência fraca ainda está vivo deve ser feito usando a expressão ref() is not None
. Normalmente, o código da aplicação que precisa usar um objeto de referência deve seguir este padrão:
# 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()
Usar um teste separado para “vivacidade” cria condições de corrida em aplicações que usam mais de uma thread; uma outra thread pode fazer com que uma referência fraca seja invalidada antes que a referência fraca seja chamada; o idioma mostrado acima é seguro em aplicações que usam mais de uma thread, bem como em aplicações de thread única.
Versões especializadas de objetos ref
podem ser criadas por meio de subclasse. Isso é usado na implementação do WeakValueDictionary
para reduzir a sobrecarga de memória para cada entrada no mapeamento. Isso pode ser mais útil para associar informações adicionais a uma referência, mas também pode ser usado para inserir processamento adicional em chamadas para recuperar o referente.
Este exemplo mostra como uma subclasse de ref
pode ser usada para armazenar informações adicionais sobre um objeto e afetar o valor retornado quando o referente é acessado:
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
Exemplo¶
Este exemplo simples mostra como uma aplicação pode usar IDs de objeto para recuperar objetos que ele viu antes. Os IDs dos objetos podem então ser usados em outras estruturas de dados sem forçar os objetos a permanecerem vivos, mas os objetos ainda podem ser recuperados por ID se o fizerem.
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]
Objetos finalizadores¶
O principal benefício de usar finalize
é que ele simplifica o registro de um retorno de chamada sem precisar preservar o objeto finalizador retornado. Por exemplo
>>> 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!
O finalizador pode ser chamado diretamente também. No entanto, o finalizador vai invocar a função de retorno no máximo uma vez.
>>> 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
Você pode desfazer o registro de um finalizador usando seu método detach()
. Isso elimina o finalizador e retorna os argumentos passados ao construtor quando ele foi criado.
>>> 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
A menos que você defina o atributo atexit
como False
, um finalizador será chamado quando o programa sair se ele ainda estiver vivo. Por exemplo
>>> obj = Object()
>>> weakref.finalize(obj, print, "obj dead or exiting")
<finalize object at ...; for 'Object' at ...>
>>> exit()
obj dead or exiting
Comparing finalizers with __del__()
methods¶
Suponha que queremos criar uma classe cujas instâncias representam diretórios temporários. Os diretórios devem ser excluídos com seus conteúdos quando o primeiro dos seguintes eventos ocorrer:
o objeto é um lixo coletado,
the object’s
remove()
method is called, oro programa finaliza.
We might try to implement the class using a __del__()
method as
follows:
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()
Starting with Python 3.4, __del__()
methods no longer prevent
reference cycles from being garbage collected, and module globals are
no longer forced to None
during interpreter shutdown.
So this code should work without any issues on CPython.
However, handling of __del__()
methods is notoriously implementation
specific, since it depends on internal details of the interpreter’s garbage
collector implementation.
Uma alternativa mais robusta pode ser definir um finalizador que faça referência apenas às funções e objetos específicos de que necessita, em vez de ter acesso ao estado completo do objeto:
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
Definido assim, nosso finalizador recebe apenas uma referência aos detalhes que ele precisa para limpar o diretório apropriadamente. Se o objeto nunca for coletado como lixo, o finalizador ainda será chamado na saída.
A outra vantagem dos finalizadores baseados em referências fracas é que eles podem ser usados para registrar finalizadores para classes onde a definição é controlada por terceiros, como executar código quando um módulo é descarregado:
import weakref, sys
def unloading_module():
# implicit reference to the module globals from the function body
weakref.finalize(sys.modules[__name__], unloading_module)
Nota
Se você criar um objeto finalizador em uma thread em um daemon assim que o programa sair, então há a possibilidade de que o finalizador não seja chamado na saída. No entanto, em um thread em um daemon atexit.register()
, try: ... finally: ...
e with: ...
não garantem que a limpeza ocorra também.