(Можно непосредственно перейти к вопросу, далее вниз, и пропустить введение.)
Существует общая проблема с выбором объектов Python из пользовательских классов:
# This is program dumper.py
import pickle
class C(object):
pass
with open('obj.pickle', 'wb') as f:
pickle.dump(C(), f)
Фактически, попытка вернуть объект из другой программы loader.py
с помощью
# This is program loader.py
with open('obj.pickle', 'rb') as f:
obj = pickle.load(f)
приводит к
AttributeError: 'module' object has no attribute 'C'
Фактически, класс выбирается по имени ("C"), и программа loader.py
ничего не знает о C
.Общее решение состоит в импорте с
from dumper import C # Objects of class C can be imported
with open('obj.pickle', 'rb') as f:
obj = pickle.load(f)
. Однако у этого решения есть несколько недостатков, включая тот факт, что все классы, на которые ссылаются протравленные объекты, должны быть импортированы (их может быть много);кроме того, локальное пространство имен загрязняется именами из программы dumper.py
.
Теперь решение этой проблемы состоит в том, чтобы полностью выполнить квалификацию объектов перед засолкой:
# 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
Отбор с оригиналомПрограмма loader.py
, описанная выше, теперь работает напрямую (нет необходимости делать from dumper import C
).
Вопрос : Теперь другие классы из dumper.py
автоматически выбираются автоматически при травлении, иЯ хотел бы знать, как это работает, и является ли это надежным, документированным поведением:
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
Теперь также работает отладка с оригинальной программой loader.py
(не нужно делать from dumper import C
);print obj.d
дает полностью квалифицированный класс, что я нахожу удивительным:
<dumper.D object at 0x122e130>
Это поведение очень удобно, поскольку только верхний, протравленный объект должен быть полностью квалифицирован с помощью модуляимя (dumper.C()
).Но является ли это поведение надежным и задокументированным?почему классы подвергаются травлению по имени ("D"), но при отмене выбора решается, что атрибут self.d
относится к классу dumper.D
(а не к некоторому локальному D
классу)?
PS: уточненный вопрос : Я только что заметил несколько интересных деталей, которые могут указывать на ответ на этот вопрос:
В программе травления dumper.py
, print self.d
отпечатки <__main__.D object at 0x2af450>
,с первой dumper.py
программой (без import dumper
).С другой стороны, выполнение import dumper
и создание объекта с dumper.C()
в dumper.py
приводит к print self.d
print <dumper.D object at 0x2af450>
: атрибут self.d
автоматически определяется Python!Таким образом, похоже, что модуль pickle
не играет никакой роли в хорошем поведении расслоения, описанном выше.
Таким образом, на самом деле возникает вопрос: почему Python преобразует D()
в полностью квалифицированный dumper.D
ввторой случай?это где-то задокументировано?