O módulo weakref permite criar referências que apontam para um objeto sem impedir que ele seja coletado pelo garbage collector. Em uma referência normal, o objeto permanece vivo enquanto existir ao menos um vínculo forte. Em uma referência fraca, o vínculo pode ser consultado enquanto o objeto existe, mas não aumenta sua contagem de referências nem prolonga artificialmente seu ciclo de vida.
Esse recurso é útil em caches, registros de objetos, mapas de metadados, observers, árvores de componentes e estruturas que não devem ser proprietárias dos elementos armazenados. Referências fracas também ajudam a evitar ciclos de vida acidentais, mas não substituem uma arquitetura clara de ownership. O desenvolvedor precisa entender quando o objeto pode desaparecer e como o código reage a essa situação.
Referência forte e referência fraca
Uma variável comum mantém uma referência forte.
objeto = MinhaClasse()
alias = objeto
Enquanto objeto ou alias existir, a instância permanece acessível. Com weakref.ref(), a referência pode deixar de apontar para uma instância válida quando todas as referências fortes forem removidas.
import weakref
objeto = MinhaClasse()
referencia = weakref.ref(objeto)
print(referencia() is objeto)
del objeto
print(referencia())
A chamada referencia() devolve o objeto vivo ou None depois da coleta.
Nem todo objeto aceita weakref
Instâncias de classes definidas pelo usuário normalmente aceitam referências fracas. Muitos tipos embutidos, como list e dict, não aceitam diretamente, embora subclasses possam aceitar em determinadas condições.
import weakref
try:
weakref.ref([])
except TypeError as erro:
print(erro)
Antes de construir uma API genérica, trate TypeError ou documente que os objetos precisam oferecer suporte a weak references.
Classes com __slots__
Ao usar __slots__, inclua "__weakref__" para permitir referências fracas.
class Usuario:
__slots__ = ("nome", "__weakref__")
def __init__(self, nome):
self.nome = nome
Sem esse slot especial, weakref.ref(instancia) gera TypeError. Isso é uma decisão de layout da classe e deve ser tomada antes da distribuição da API.
Evite a corrida entre teste e uso
Não teste a referência e depois a chame novamente, porque o objeto pode desaparecer entre as operações em código concorrente.
objeto = referencia()
if objeto is not None:
objeto.executar()
Guardar o resultado em uma variável local cria uma referência forte temporária durante o uso.
Callbacks de finalização da referência
weakref.ref() pode receber um callback chamado quando o objeto referenciado está prestes a desaparecer.
import weakref
def removido(referencia):
print("objeto coletado")
objeto = MinhaClasse()
referencia = weakref.ref(objeto, removido)
O callback recebe a própria referência fraca, não o objeto original. Nesse momento, recuperar o objeto normalmente já não é possível.
Não capture o objeto no callback
Um erro comum é criar uma closure que mantém uma referência forte ao próprio objeto.
def criar_callback(objeto):
def callback(referencia):
print(objeto)
return callback
Esse padrão impede a coleta e anula o propósito da weak reference. Capture apenas identificadores, strings ou metadados independentes.
weakref.proxy
weakref.proxy() cria um proxy que encaminha operações ao objeto sem exigir a chamada ().
import weakref
objeto = MinhaClasse()
proxy = weakref.proxy(objeto)
proxy.executar()
Se o objeto já tiver sido coletado, o proxy gera ReferenceError. Use quando a sintaxe transparente realmente melhorar a API; caso contrário, ref() torna a possibilidade de ausência mais explícita.
Proxy para objetos chamáveis
Funções e objetos com __call__ podem gerar CallableProxyType. O proxy continua sem possuir o alvo.
Não armazene um proxy em um local que exige disponibilidade garantida. A chamada precisa aceitar ReferenceError como parte normal do ciclo de vida.
WeakValueDictionary
WeakValueDictionary mantém chaves fortes e valores fracos. Quando um valor não possui mais referências fortes, a entrada desaparece automaticamente.
import weakref
cache = weakref.WeakValueDictionary()
objeto = MinhaClasse()
cache["principal"] = objeto
print("principal" in cache)
del objeto
print("principal" in cache)
É útil para interning, factories e caches que não devem prolongar a vida dos resultados.
Cache fraco não garante retenção
Uma entrada pode sumir logo após a criação se nenhum caller mantiver referência forte.
cache[chave] = construir()
Se construir() devolver um objeto sem outro proprietário, ele pode desaparecer imediatamente. O caller que precisa do valor deve armazená-lo em uma variável forte.
WeakKeyDictionary
WeakKeyDictionary mantém chaves fracas e valores fortes. Quando a chave desaparece, a associação é removida.
import weakref
metadados = weakref.WeakKeyDictionary()
usuario = Usuario("Ana")
metadados[usuario] = {"visitas": 1}
É uma alternativa a adicionar atributos em objetos de terceiros e pode armazenar dados auxiliares associados à vida da instância.
Igualdade e identidade nas chaves
Objetos diferentes que são considerados iguais podem interagir de forma inesperada em mapas fracos. O dicionário segue regras de hash e igualdade, enquanto a remoção depende da vida do objeto usado como chave.
Prefira chaves cuja identidade e igualdade sejam estáveis. Não altere campos usados em __hash__ depois da inserção.
WeakSet
WeakSet armazena objetos fracamente, removendo membros coletados.
import weakref
observadores = weakref.WeakSet()
observadores.add(listener)
for observador in list(observadores):
observador.atualizar()
O snapshot com list() pode ser útil quando callbacks alteram o conjunto durante a iteração.
Observers sem vazamento
Um sistema de eventos que mantém listeners em uma lista normal pode impedir que telas, componentes ou controllers sejam coletados. Um WeakSet reduz esse risco quando os listeners são objetos.
Ainda é necessário definir o que acontece quando nenhum listener existe e como funções, métodos e closures são registrados.
WeakMethod
Um método bound temporário não pode ser tratado da mesma forma que uma instância comum, porque acessar objeto.metodo cria um novo objeto de método. WeakMethod guarda uma referência fraca recuperável ao par instância e função.
import weakref
referencia = weakref.WeakMethod(objeto.processar)
metodo = referencia()
if metodo is not None:
metodo()
Esse padrão é especialmente útil em registradores de callbacks orientados a objetos.
finalize
weakref.finalize() registra uma função para ser chamada quando um objeto é coletado.
import weakref
recurso = Recurso()
finalizador = weakref.finalize(recurso, fechar_handle, recurso.handle)
O finalizador permanece vivo até executar ou ser cancelado. Ele costuma ser mais conveniente e robusto que callbacks diretos de ref().
Não use finalização como mecanismo principal
A liberação determinística deve usar with, close() ou uma API explícita. A coleta pode ocorrer tarde, em ordem inesperada ou durante o encerramento do interpretador.
Use finalize como rede de segurança, não como transação, commit, flush crítico ou fechamento que precisa ocorrer em prazo definido.
detach e alive
Um finalizador possui a propriedade alive. detach() remove e devolve as informações registradas sem executar a função. Uma chamada direta ao finalizador executa apenas uma vez.
if finalizador.alive:
finalizador()
Isso permite cleanup explícito enquanto preserva a proteção contra duplicidade.
Ordens de finalização
Durante o shutdown, finalizadores vivos podem ser chamados em ordem reversa de criação, conforme as regras da implementação. Não construa dependências complexas entre eles.
Um finalizador não deve depender de módulos globais que talvez já estejam parcialmente desmontados. Passe funções e valores necessários diretamente.
Ciclos de referência
Referências fracas podem quebrar vínculos não proprietários em grafos de objetos. Por exemplo, um filho pode possuir uma referência fraca ao pai quando o pai já possui fortemente o filho.
O garbage collector moderno consegue resolver muitos ciclos, mas weak references continuam úteis para expressar ownership e evitar retenção por registradores externos.
Garbage collection não é imediata em todos os runtimes
Em CPython, a contagem de referências costuma liberar muitos objetos rapidamente. Outras implementações podem coletar em momentos diferentes. Mesmo em CPython, ciclos dependem do coletor cíclico.
Não escreva testes que exigem que o callback ocorra exatamente após del. Quando necessário em testes controlados, gc.collect() pode solicitar uma coleta, mas não deve virar requisito da aplicação.
Threads e segurança
Estruturas fracas não transformam operações compostas em atômicas. Um objeto pode desaparecer entre observações, e dicionários podem mudar durante iteração.
Use locks quando várias threads atualizam o mesmo registrador. Sempre obtenha o alvo uma única vez e mantenha a referência local durante o uso.
Asyncio e tasks
O event loop pode manter apenas referências específicas a tasks em certos contextos. A documentação de asyncio recomenda que a aplicação mantenha referências fortes para tasks de background e remova-as ao concluir.
Não presuma que uma estrutura fraca é adequada para gerenciar tarefas cuja execução deve ser garantida.
Desempenho
Weak references têm overhead de objetos auxiliares, callbacks e manutenção de estruturas. Elas também tornam o lifecycle menos previsível para quem lê o código.
Use-as quando resolvem um problema real de ownership ou cache. Uma lista normal com remoção explícita pode ser mais simples e rápida.
Debugging
weakref.getweakrefcount(objeto) informa quantas referências fracas e proxies apontam para o objeto. getweakrefs() devolve a lista correspondente.
print(weakref.getweakrefcount(objeto))
print(weakref.getweakrefs(objeto))
Essas funções ajudam em diagnóstico, mas o estado pode mudar imediatamente em código concorrente.
Testes recomendados
Teste o objeto vivo, coleta após remoção da última referência forte, callback executado uma vez, finalizador explícito, cancelamento, objetos sem suporte a weakref, classes com slots, concorrência e ausência inesperada no cache.
Evite depender da ordem global de coleta entre vários objetos.
Erros comuns
Os erros mais frequentes são usar weak reference quando o cache precisa reter valores, capturar o alvo no callback, reutilizar um proxy depois da coleta, esquecer __weakref__ em slots, esperar coleta imediata, usar finalizador para commit crítico e não manter referência forte para callbacks ou tasks que precisam continuar vivos.
Conclusão
weakref permite representar relações não proprietárias e construir caches que cedem espaço automaticamente quando os objetos deixam de ser usados. Use ref para acesso explícito, proxies para sintaxe transparente, dicionários e sets fracos para registros e finalize como proteção adicional de cleanup.
Mantenha o ownership principal explícito, aceite que o alvo pode desaparecer e prefira context managers para liberação determinística. Consulte a documentação oficial de weakref e o artigo sobre contextlib no Python.







