Mic*_*ley 90 python function pickle
我正在尝试通过网络连接传输功能(使用asyncore).是否有一种简单的方法来序列化python函数(在这种情况下,至少,没有副作用)这样的传输?
理想情况下,我希望有一对类似的功能:
def transmit(func):
obj = pickle.dumps(func)
[send obj across the network]
def receive():
[receive obj from the network]
func = pickle.loads(s)
func()
Run Code Online (Sandbox Code Playgroud)
Bri*_*ian 114
您可以序列化函数字节码,然后在调用者上重建它.所述编组模块可用于序列化代码对象,然后可将其重新组装成一个函数.即:
import marshal
def foo(x): return x*x
code_string = marshal.dumps(foo.func_code)
Run Code Online (Sandbox Code Playgroud)
然后在远程进程中(在传输code_string之后):
import marshal, types
code = marshal.loads(code_string)
func = types.FunctionType(code, globals(), "some_func_name")
func(10) # gives 100
Run Code Online (Sandbox Code Playgroud)
一些警告:
marshal的格式(任何python字节码)在主要python版本之间可能无法兼容.
只适用于cpython实现.
如果函数引用了你需要拾取的全局变量(包括导入的模块,其他函数等),你也需要序列化它们,或者在远程端重新创建它们.我的例子只是为它提供了远程进程的全局命名空间.
您可能需要做更多工作来支持更复杂的情况,例如闭包或生成器函数.
Jos*_*sen 36
查看Dill,它扩展了Python的pickle库以支持更多种类型,包括函数:
>>> import dill as pickle
>>> def f(x): return x + 1
...
>>> g = pickle.dumps(f)
>>> f(1)
2
>>> pickle.loads(g)(1)
2
Run Code Online (Sandbox Code Playgroud)
它还支持对函数闭包中对象的引用:
>>> def plusTwo(x): return f(f(x))
...
>>> pickle.loads(pickle.dumps(plusTwo))(1)
3
Run Code Online (Sandbox Code Playgroud)
这完全取决于您是否在运行时生成函数:
如果你这样做 - inspect.getsource(object)将不能用于动态生成的函数,因为它从.py文件中获取对象的源,因此只有在执行之前定义的函数才能作为源检索.
如果您的函数无论如何都放在文件中,为什么不让接收者访问它们,只传递模块和函数名称.
我能想到的动态创建函数的唯一解决方案是在传输之前将函数构造为字符串,传输源,然后eval()在接收器端构建函数.
编辑:marshal解决方案看起来也很聪明,不知道你可以序列化其他内置的内容
在现代 Python 中,您可以 pickle 函数和许多变体。考虑一下这个
import pickle, time
def foobar(a,b):
print("%r %r"%(a,b))
Run Code Online (Sandbox Code Playgroud)
你可以腌制它
p = pickle.dumps(foobar)
q = pickle.loads(p)
q(2,3)
Run Code Online (Sandbox Code Playgroud)
你可以腌制封闭物
import functools
foobar_closed = functools.partial(foobar,'locked')
p = pickle.dumps(foobar_closed)
q = pickle.loads(p)
q(2)
Run Code Online (Sandbox Code Playgroud)
即使闭包使用局部变量
def closer():
z = time.time()
return functools.partial(foobar,z)
p = pickle.dumps(closer())
q = pickle.loads(p)
q(2)
Run Code Online (Sandbox Code Playgroud)
但如果使用内部函数关闭它,它将失败
def builder():
z = 'internal'
def mypartial(b):
return foobar(z,b)
return mypartial
p = pickle.dumps(builder())
q = pickle.loads(p)
q(2)
Run Code Online (Sandbox Code Playgroud)
有错误
pickle.PicklingError:无法 pickle <function mypartial at 0x7f3b6c885a50>:未找到 __ main __.mypartial
使用 Python 2.7 和 3.6 进行测试