我有以下设置:
a.py
:
class A(object):
def __init__(self, name):
self.name = name
def a(self):
print('yow {}!'.format(self.name))
b.py
:
class B(object):
def __init__(self, obj):
self.obj = obj
sender.py
:
from a import A
from b import B
message = pickle.dumps(B(A('Martin')))
receiver.py
:
my_b = pickle.loads(message)
my_a = my_b.obj
my_a.a()
输出:yow Martin!
在sender.py
中,我挑选了作为对象b
的载体的对象a
。然后我通过RabbitMQ将腌制对象b
发送到另一个进程。在receiver.py
(这是另一个进程)中,我通过RabbitMQ收到消息,unpickle对象b
和魔术B
和A
自动导入。我能控制进口的东西吗?我希望工作者receiver.py
尽可能少地使用内存。但是如果模块在没有我控制的情况下导入,它会很快膨胀。
有人可以解释一下pickle如何进口东西以及如何处理它?</ p>
答案 0 :(得分:2)
它使用__module__
和A
的{{1}}属性:
B
如果要控制导入的内容,可以构建python包,以便>>> A.__module__
'a'
>>> __import__(A.__module__)
<module 'a' from 'a.py'>
不会加载太多对象。
答案 1 :(得分:2)
需要什么样的控制?正如您从源代码中看到的那样,当您运行pickle.loads(content)
时,它确实会:
def loads(str):
file = StringIO(str)
return Unpickler(file).load()
然后有一些魔力。它将一个字符串作为一个文件读出并发送它的&#39;内容基于特定密钥:
GLOBAL = 'c' # push self.find_class(modname, name); 2 string args
INST = 'i' # build & push class instance
加载功能本身:
def load(self):
"""Read a pickled object representation from the open file.
Return the reconstituted object hierarchy specified in the file.
"""
...
read = self.read # self.read = file.read, which is StringIO's read()
dispatch = self.dispatch
try:
while 1:
key = read(1)
dispatch[key](self) # this function call makes a future import.
except _Stop, stopinst:
return stopinst.value
您对方法find_class()
感兴趣,该方法在其他几个load functions
(load_inst()
和load_global()
)中使用:
def find_class(self, module, name):
# Subclasses may override this:
__import__(module) # straight-forward import, you can ovveride it.
mod = sys.modules[module]
klass = getattr(mod, name)
return klass
例如,load_inst()
函数:
def load_inst(self):
module = self.readline()[:-1]
name = self.readline()[:-1]
klass = self.find_class(module, name)
# Now module is imported and ready to be used:
self._instantiate(klass, self.marker())
dispatch[INST] = load_inst
因此,如果要控制可导入的名称空间或模块,则需要子类Unpickler
并覆盖find_class()
以符合您的目标。我的回答对你有帮助吗?
答案 2 :(得分:1)
pickle
需要导入模块a
和b
才能加载类A
和B
,这些类需要重新构建您的宾语。我拿了你的例子,只是将a.py重命名为aaaa.py,将b.py重命名为bbbb.py.现在,如果我们打印sender.py实际发送的消息(pickled对象),你会看到:
ccopy_reg
_reconstructor
p0
(cbbbb
B
p1
c__builtin__
object
p2
Ntp3
Rp4
(dp5
S'obj'
p6
g0
(caaaa
A
p7
g2
Ntp8
Rp9
(dp10
S'name'
p11
S'Martin'
p12
sbsb.
您不需要了解所有内容,但请注意bbbb
后跟B
,aaaa
后跟A
在那里。那就是告诉pickle
如何重建你的腌制对象。为了加载类,它必须导入定义类的模块。如果你试图搞乱pickle的机器并阻止模块被加载,那么就没有办法重建你的对象