如何解开其类存在于不同命名空间(python)中的对象?
Posted
技术标签:
【中文标题】如何解开其类存在于不同命名空间(python)中的对象?【英文标题】:How to unpickle an object whose class exists in a different namespace (python)? 【发布时间】:2013-01-09 15:36:50 【问题描述】:如果我有一个定义类的脚本:
script = """
class myClass:
def __init__(self):
self.name = 'apple'
self.color = 'green'
"""
然后在它自己的命名空间字典中执行这个脚本:
NS =
exec script in NS
然后创建一个类的实例并腌制它:
a = NS['myClass']()
import pickle
save = pickle.dumps(a)
现在如果我尝试解开它:
load = pickle.loads(save)
我得到了错误
AttributeError: 'module' object has no attribute 'myClass'
我认为这不起作用,因为 python 不知道在哪里可以找到 myClass 以重建对象。但是 myClass 确实存在于 NS 字典中。有没有办法告诉 pickle 在哪里可以找到它正在加载的对象的类?
【问题讨论】:
【参考方案1】:我发现了一个解决方案。似乎问题是在 dict 中执行代码会阻止 python 找出类的定义位置。解决方法是创建一个空模块,执行模块中的代码,然后将该模块添加到sys.modules中让python知道。
script = """
class myClass:
def __init__(self):
self.name = 'apple'
self.color = 'green'
"""
import imp, sys
moduleName = 'custom'
module = imp.new_module(moduleName)
exec script in module.__dict__
sys.modules[moduleName] = module
现在可以腌制和取消腌制类的实例:
import pickle
a = module.myClass()
s = pickle.dumps(a)
b = pickle.loads(s)
【讨论】:
这个解决方案有点 hackish IMO。但它有效!所以谢谢。就我而言,我无法控制泡菜的接收端。否则可以使用 Borealid 的答案【参考方案2】:您实际上可以更进一步,让对象将自身重构为您想要的任何类型。
import pickle
import copy_reg
class myClass(object):
def __init__(self):
self.apple = 'banana'
class otherclass(object):
def __init__(self):
self.apple = 'existential woe'
def pickle_an_object(o):
print "pickling %s" % str(o)
return otherclass, (o.apple,)
copy_reg.pickle(myClass, pickle_an_object)
foo = myClass()
s = pickle.dumps(foo)
del myClass
del otherclass
class otherclass(object):
def __init__(self, appletype):
self.apple = 'not %s' % appletype
o2 = pickle.loads(s)
print o2.apple
基本思想是将您的类打包成某种“特洛伊木马”,在这种情况下,它的重建会导致实例化与原来不同的类。
酸洗侧的otherclass
包含什么无关紧要。重要的是它与“目标”类存在于同一模块路径中 - pickle
只是将模块名称的字符串表示形式放入序列化流中。
所以,详细分解上面代码中发生的事情:
我们为myClass
注册了一个自定义pickler。这可以通过copy_reg
或__reduce_ex__
函数来完成。
我们的自定义pickler 说“pickle this as an instance of otherclass
”(这是一个假人。您不需要在酸洗方面需要otherclass
的“真实”内容,因为所有进入泡菜的是模块/类名)。
我们腌制对象并“将其通过网络发送”到otherclass
的真实版本所在的位置。
在远程端,otherclass
使用自定义酸洗函数返回的元组中的数据进行实例化。
Python 可以非常强大!
【讨论】:
这一切都很整洁,但它如何回答最初的问题? @JohnY 您可以将类从 unpickler 的命名空间中 unpickle 到任意类的实例中。您将myClass
设置为foomodule.myClass
,然后在调用pickle.loads
之前说foomodule.myClass = NS['myClass']
。以上是关于如何解开其类存在于不同命名空间(python)中的对象?的主要内容,如果未能解决你的问题,请参考以下文章
列出存在于另一个模型中的所有关联模型记录,该模型存在于 rails 中的另一个命名空间中
python基础 13 类命名空间于对象实例的命名空间,组合方法
如何解决 .net 标准中的命名空间“System.Configuration”错误中不存在类型或命名空间名称“ConfigurationManager”?