有没有简单的方法将Python函数序列化?

141 投票
12 回答
86433 浏览
提问于 2025-04-15 13:29

我正在尝试通过网络连接传输一个函数(使用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()

12 个回答

13

最简单的方法可能就是用 inspect.getsource(object) 这个命令(可以查看 inspect模块 的相关内容),它会返回一个字符串,里面包含了某个函数或方法的源代码。

61

看看这个 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

它还支持对函数闭包中对象的引用:

>>> def plusTwo(x): return f(f(x))
...
>>> pickle.loads(pickle.dumps(plusTwo))(1)
3
147

你可以把函数的字节码进行序列化,然后在调用者那边再重建它。可以使用marshal模块来序列化代码对象,这样就能把它们重新组装成一个函数。比如:

import marshal
def foo(x): return x*x
code_string = marshal.dumps(foo.__code__)

然后在远程进程中(在传输了code_string之后):

import marshal, types

code = marshal.loads(code_string)
func = types.FunctionType(code, globals(), "some_func_name")

func(10)  # gives 100

有几点需要注意:

  • marshal的格式(任何Python字节码也是如此)可能在不同的Python大版本之间不兼容。

  • 这个方法只适用于CPython实现。

  • 如果函数引用了全局变量(包括导入的模块、其他函数等),你需要把这些也序列化,或者在远程端重新创建它们。我的例子只是给了远程进程的全局命名空间。

  • 如果要支持更复杂的情况,比如闭包或生成器函数,可能还需要做更多的工作。

撰写回答