Como funciona a qualificação completa automática de nomes de classe, em Python? [relevante para decapagem de objetos]
(É possível pular diretamente para a pergunta, mais abaixo, e pular a introdução.)
Existe uma dificuldade comum ao selecionar objetos Python de classes definidas pelo usuário:
# This is program dumper.py
import pickle
class C(object):
pass
with open('obj.pickle', 'wb') as f:
pickle.dump(C(), f)
Na verdade, tentando recuperar o objeto de outro programaloader.py
com
# This is program loader.py
with open('obj.pickle', 'rb') as f:
obj = pickle.load(f)
resulta e
AttributeError: 'module' object has no attribute 'C'
De fato, a classe é selecionada por nome ("C"), e oloader.py
programa @ não sabe nada sobre oC
. Uma solução comum consiste em importar com
from dumper import C # Objects of class C can be imported
with open('obj.pickle', 'rb') as f:
obj = pickle.load(f)
No entanto, esta solução tem algumas desvantagens, incluindo o fato de que todas as classes referenciadas pelos objetos em vinagre precisam ser importadas (pode haver muitas); além disso, o espaço para nome local fica poluído por nomes dodumper.py
programa
gora, uma solução para isso consiste em objetos totalmente qualificados antes da decapage
# New dumper.py program:
import pickle
import dumper # This is this very program!
class C(object):
pass
with open('obj.pickle', 'wb') as f:
pickle.dump(dumper.C(), f) # Fully qualified class
Despickling com o originalloader.py
programa @ acima agora funciona diretamente (não é necessário fazerfrom dumper import C
).
Questã: Agora, outras classes dedumper.py
parece ser totalmente qualificado automaticamente após a decapagem, e eu gostaria de saber como isso funciona e se esse é um comportamento documentado e confiável:
import pickle
import dumper # This is this very program!
class D(object): # New class!
pass
class C(object):
def __init__(self):
self.d = D() # *NOT* fully qualified
with open('obj.pickle', 'wb') as f:
pickle.dump(dumper.C(), f) # Fully qualified pickle class
Agora, discernindo com o originalloader.py
programa @ também funciona (não é necessário fazerfrom dumper import C
);print obj.d
dá umcompletamente qualificad class, o que acho surpreendente:
<dumper.D object at 0x122e130>
Este comportamento é muito conveniente, pois apenas o objeto em conserva superior deve ser totalmente qualificado com o nome do módulo dumper.C()
). Mas esse comportamento é confiável e documentado? como é que as classes são decapadas pelo nome ("D"), mas que o unpickling decide que o decapadoself.d
atributo é da classedumper.D
(e não alguns locaisD
classe)
PS: A questão, refinado: Acabei de notar alguns detalhes interessantes que podem apontar para uma resposta a esta pergunta:
No programa de decapagemdumper.py
, print self.d
impressões<__main__.D object at 0x2af450>
, com o primeirodumper.py
programa (aquele semimport dumper
). Por outro lado, fazerimport dumper
e criando o objeto comdumper.C()
emdumper.py
makesprint self.d
impressão<dumper.D object at 0x2af450>
: aself.d
atributo @ é qualificado automaticamente pelo Python! Então, parece que opickle
módulo @ não tem nenhum papel no bom comportamento de remoção de carga descrito acim
A questão é assim: por que o Python converteD()
para o @ totalmente qualificadumper.D
, no segundo caso? isso está documentado em algum lugar?