序列化和反序列化lambda

mat*_*ieu 16 python lambda pickle

我想序列化机器A并在机器B上反序列化python lambda.这有几个明显的问题:

  • pickle模块不会序列化或反序列化代码.它只序列化类/方法/函数的名称
  • 我在谷歌找到的一些答案建议使用低级编组模块来序列化lambda的func_code属性,但是他们无法描述如何从反序列化的代码对象重建一个函数对象
  • marhshal(l.func_code)不会序列化与lambda相关联的闭包,导致检测给定lambda何时真正需要闭包并警告用户他正在尝试序列化使用闭包的lambda的问题

因此,我的问题:

  • 如何从反序列化(解组)代码对象重建函数?
  • 如果没有关联的闭包,如何检测给定的lambda将无法正常工作?

Dav*_*ver 19

令人惊讶的是,检查lambda是否在没有相关闭合的情况下工作实际上相当容易.根据数据模型文档,您只需检查func_closure属性:

>>> def get_lambdas():
...     bar = 42
...     return (lambda: 1, lambda: bar)
...
>>> no_vars, vars = get_lambdas()
>>> print no_vars.func_closure
None
>>> print vars.func_closure
(<cell at 0x1020d3d70: int object at 0x7fc150413708>,)
>>> print vars.func_closure[0].cell_contents
42
>>>

然后序列化+加载lambda非常简单:

>>> import marshal, types
>>> old = lambda: 42
>>> old_code_serialized = marshal.dumps(old.func_code)
>>> new_code = marshal.loads(old_code_serialized)
>>> new = types.FunctionType(new_code, globals())
>>> new()
42

值得一看的文档FunctionType:

function(code, globals[, name[, argdefs[, closure]]])

Create a function object from a code object and a dictionary.
The optional name string overrides the name from the code object.
The optional argdefs tuple specifies the default argument values.
The optional closure tuple supplies the bindings for free variables.

请注意,您还可以提供闭包...这意味着您甚至可以序列化旧函数的闭包,然后在另一端加载它:)

  • 只是使用python 3.0+的其他人的注释.他们将`func_closure`的名称改为`__closure__`.有关详细信息,请参阅https://docs.python.org/3.0/whatsnew/3.0.html#operators-and-special-methods. (2认同)