unpickle python 对象时如何控制导入的内容?
How to control what gets imported when you unpickle python object?
我有以下设置:
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
中,我 pickle 对象 b
作为对象 a
的载体。然后我通过 RabbitMQ 将那个腌制对象 b
发送到 另一个进程 。在 receiver.py
(这是另一个进程)中,我通过 RabbitMQ 收到一条消息,unpickle 对象 b
并通过魔法 B
和 A
自动导入。我可以控制导入的内容吗?我希望 worker receiver.py
消耗尽可能少的内存。但是,如果模块在我无法控制的情况下被导入,它会很快变得臃肿。
有人可以解释 pickle 如何导入东西以及如何处理它吗?
它使用A
和B
的__module__
属性:
>>> A.__module__
'a'
>>> __import__(A.__module__)
<module 'a' from 'a.py'>
如果您想控制导入的内容,您可以构造您的 python 包,这样 from a import A
就不会加载太多对象。
需要什么样的控制?正如您从源代码中看到的那样,当您 运行 pickle.loads(content)
它实际上是:
def loads(str):
file = StringIO(str)
return Unpickler(file).load()
然后有一些魔法。它将字符串作为文件读取,并根据特定键分派其内容:
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()
以符合您的目标。我的回答对您有帮助吗?
pickle
需要导入模块 a
和 b
以加载 类 A
和 B
,它们是需要重建你的对象。我以你的例子为例,只是将 a.py 重命名为 aaaa.py,将 b.py 重命名为 bbbb.py。现在,如果我们打印 sender.py 实际发送的消息(腌制对象),您会看到:
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
如何重建你的 pickled 对象。为了加载 类,它必须导入定义了 类 的模块。如果你试图扰乱 pickle 的机器并阻止模块被加载,就不会有重建对象的方法。
我有以下设置:
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
中,我 pickle 对象 b
作为对象 a
的载体。然后我通过 RabbitMQ 将那个腌制对象 b
发送到 另一个进程 。在 receiver.py
(这是另一个进程)中,我通过 RabbitMQ 收到一条消息,unpickle 对象 b
并通过魔法 B
和 A
自动导入。我可以控制导入的内容吗?我希望 worker receiver.py
消耗尽可能少的内存。但是,如果模块在我无法控制的情况下被导入,它会很快变得臃肿。
有人可以解释 pickle 如何导入东西以及如何处理它吗?
它使用A
和B
的__module__
属性:
>>> A.__module__
'a'
>>> __import__(A.__module__)
<module 'a' from 'a.py'>
如果您想控制导入的内容,您可以构造您的 python 包,这样 from a import A
就不会加载太多对象。
需要什么样的控制?正如您从源代码中看到的那样,当您 运行 pickle.loads(content)
它实际上是:
def loads(str):
file = StringIO(str)
return Unpickler(file).load()
然后有一些魔法。它将字符串作为文件读取,并根据特定键分派其内容:
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()
以符合您的目标。我的回答对您有帮助吗?
pickle
需要导入模块 a
和 b
以加载 类 A
和 B
,它们是需要重建你的对象。我以你的例子为例,只是将 a.py 重命名为 aaaa.py,将 b.py 重命名为 bbbb.py。现在,如果我们打印 sender.py 实际发送的消息(腌制对象),您会看到:
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
如何重建你的 pickled 对象。为了加载 类,它必须导入定义了 类 的模块。如果你试图扰乱 pickle 的机器并阻止模块被加载,就不会有重建对象的方法。