我正在使用python 3.5。相当新的python,但不是编程的新手。我有三个源文件如下(我实际上正在做的简化版本):
c.py
class C:
def __init__(self, x):
self.x = x
def method(self):
print(self.x)
init.py
import shelve
from c import C
db = shelve.open("DB")
db['key1'] = C("test")
db.close()
test.py
import shelve
db = shelve.open("DB")
obj = db['key1']
obj.method() # this works
C.method(obj) # this doesn't -- 'C' not defined
db.close()
所以我运行init.py来设置我的搁置数据库。然后我运行test.py.它很高兴执行obj.method(),所以它似乎知道C类,即使我没有明确地导入它(Lutz说它存储在数据库中)。但是如果我尝试做C.method(obj)(并不是说我必须以这种方式调用它,而是使用C作为类(例如创建新对象)有用)它说&# 39; C'没有定义。但是,如果我从c import C'中添加' test.py然后它的工作原理。所以在某种程度上它似乎知道了C的定义,但是它再一次没有。我很想知道为什么会这样。
答案 0 :(得分:4)
当搁置序列化一个对象时(我相信通过腌制它),它会将导入路径存储到类中,以便稍后进行取消排序。检索对象时,pickle
会导入模块(c
)并返回C
的实例(相当于最初序列化的实例)。
到目前为止,根据您的观察结果,这对您来说并不是什么新鲜事。但是,当它导入c
时,它不会将其导入当前的命名空间。实际上,它将其导入very localized namespace。因此,虽然已导入c
模块(您可以在sys.modules
中找到它),但在当前命名空间中找不到c
或C
,因为您还没有在那里进口。
换句话说,只是导入某些内容并不会使程序中的每个模块都可以访问它。它只使其可以被导入的模块(实际范围)访问。我可以导入os
,但仅仅因为os
导入sys
并不意味着我可以立即访问sys
。我需要先导入它才能开始使用它。
>>> import os
>>> sys
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'sys' is not defined
>>> os.sys
<module 'sys' (built-in)>
>>> import sys
>>> sys
<module 'sys' (built-in)>
答案 1 :(得分:1)
由于mgilson's answer中所述的原因,您所拥有的内容无效。
解决问题的方法是从模块手动导入类并将类分配给名称C
- 这些行(使用Python 3.5.1测试):
import shelve
db = shelve.open("DB")
obj = db['key1']
obj.method() # this works
## Begin added code ##
classname = obj.__class__.__name__
module_name = obj.__module__
module = __import__(module_name, globals(), locals(), [classname], 0)
globals()[classname] = getattr(module, classname)
## Added code end ##
C.method(obj) # this also works now
db.close()