2009-08-10 75 views
79

我试图通过网络连接(使用异步)传输一个函数。有没有一种简单的方法来序列化一个Python函数(至少在这种情况下,将不会有副作用),像这样传输?有没有简单的方法来腌制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() 
+3

有你试过你的代码? – monkut 2009-08-10 07:30:08

回答

105

您可以将函数字节码序列化,然后在调用者上重构它。 marshal模块可用于序列化代码对象,然后可将其重新组合为一个函数。即:

import marshal, types 

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

func(10) # gives 100 

几个注意事项:

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

然后在远程进程(转移CODE_STRING后)

  • 元帅的格式(任何的Python字节码为此事)不得在主要的python版本之间兼容。

  • 只适用于cpython实现。

  • 如果函数需要引用全局变量(包括导入的模块,其他函数等),则还需要对它们进行序列化,或者在远程端重新创建它们。我的例子只是给它提供了远程进程的全局名称空间。

  • 您可能需要做更多的工作来支持更复杂的情况,例如关闭或生成器函数。

+1

在Python 2.5中,不推荐使用“new”模块。我相信'new.function'应该替换为'types.FunctionType',之后是“导入类型”。 – EOL 2009-08-10 10:31:49

+0

@EOL:好点 - 我更新了代码来使用类型模块。 – Brian 2009-08-10 11:26:49

+1

谢谢。这正是我所期待的。基于一些粗略的测试,它可以像发电机那样工作。 – 2009-08-10 17:47:04

10

最简单的方法可能是inspect.getsource(object)(见inspect module),它返回一个字符串的源代码的功能或方法。

+0

这看起来不错,只是函数名是在代码中明确定义的,稍有问题。我可以将代码的第一行去掉,但通过执行类似'def \/n func():'的方法可以解决这个问题。我可以使用函数本身来腌制函数的名称,但是我不能保证名称不会相互冲突,或者我不得不将函数放入一个包装中,但这仍然不是最干净的解决方案,但它可能不得不这样做。 – 2009-08-10 08:01:11

+0

请注意,inspect模块实际上只是询问函数在哪里定义,然后从源代码文件中读取这些行 - 这几乎不复杂。 – 2009-08-10 09:05:24

+1

您可以使用它的.__ name__属性找到该函数的名称。你可以在^ def \ s * {name} \ s *上做一个正则表达式替换(并给出它你喜欢的任何名称,但它不是万无一失的,但它对大多数事情都有效) – 2009-08-10 09:09:08

13
+0

我需要坚持使用标准库 – 2009-08-10 07:48:32

+15

但是,这并不意味着你不能*看* Pyro的代码,看看它是如何完成的:) – 2009-08-10 09:45:37

+0

链接断开 - 这里是Pyro文档 - http://packages.python。 org/Pyro4/ – 2012-08-27 09:43:52

5

这一切都取决于你是否产生在功能运行与否:

如果你这样做 - inspect.getsource(object)不会为动态生成的函数的工作,因为它得到对象的源从.py文件,因此,只有功能在执行之前定义可以作为源检索。

如果你的函数放在文件中,为什么不让接收者访问它们,只传递模块和函数名称。

我能想到的动态创建函数的唯一解决方案是在传输之前将函数构造为字符串,传输源,然后在接收端对其进行构造。

编辑:marshal解决方案看起来也很聪明,不知道你可序列化的东西其他腋臭内置插件

1

使用此模块的基本功能包括查询,再加上你在获得最佳的压缩线;请参阅指导性源代码:

y_serial。py模块::使用SQLite的仓库Python对象

“Serialization + persistance ::在几行代码中,将Python对象压缩并注释到SQLite中;然后稍后按关键字按顺序检索它们,而不使用任何SQL。模块用于数据库来存储无模式数据。“

http://yserial.sourceforge.net

25

退房Dill,它扩展了Python的泡菜库,以支持更多种类的类型,包括功能:

>>> 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 
+1

莳萝也做了很好的工作,从函数和lambdas获取源代码并将它们保存到磁盘,如果你更喜欢对象酸洗。 – 2014-01-23 04:03:29

相关问题