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?

questionAnswers(2)

yourAnswerToTheQuestion