来自shelve

时间:2016-06-21 20:05:29

标签: python python-3.x

我正在使用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的定义,但是它再一次没有。我很想知道为什么会这样。

2 个答案:

答案 0 :(得分:4)

当搁置序列化一个对象时(我相信通过腌制它),它会将导入路径存储到类中,以便稍后进行取消排序。检索对象时,pickle会导入模块(c)并返回C的实例(相当于最初序列化的实例)。

到目前为止,根据您的观察结果,这对您来说并不是什么新鲜事。但是,当它导入c时,它不会将其导入当前的命名空间。实际上,它将其导入very localized namespace。因此,虽然已导入c模块(您可以在sys.modules中找到它),但在当前命名空间中找不到cC,因为您还没有在那里进口。

换句话说,只是导入某些内容并不会使程序中的每个模块都可以访问它。它只使其可以被导入的模块(实际范围)访问。我可以导入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()