我一直在处理有关lambda
功能及其无法pickled
的错误。我经常使用lambda
函数作为一次性使用函数,当我必须单独重新创建功能形式的简单lambda函数以用于酸洗时,它极大地降低了我的工作流程效率。
有没有办法将lambda
及其所有参数转换为function
中的Python 3.6.1
对象?
lambda_func = lambda x: x.split(" ")
def func(x):
return x.split(" ")
input_string = "Darth Plagueis was a Dark Lord of the Sith"
# Function Version
func(input_string)
# ['Darth', 'Plagueis', 'was', 'a', 'Dark', 'Lord', 'of', 'the', 'Sith']
lambda_func(input_string)
# ['Darth', 'Plagueis', 'was', 'a', 'Dark', 'Lord', 'of', 'the', 'Sith']
def lambda2func(lambda_func):
#...
return func_version
答案 0 :(得分:1)
pickle
不保存代码对象,仅保存其名称。但是,给函数起一个名字不足以使其可腌制,因为unpickle
通过导入名字来反序列化它。自然地,这意味着解开运行时必须 importable 。由于这个原因,带有名称的函数def
仍然可能无法泡菜。因此,即使您可以将lambda转换为命名函数,也仍然行不通:
>>> import pickle
>>> def foo():
... def bar():
... pass
... return bar
...
>>> pickle.dumps(foo())
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: Can't pickle local object 'foo.<locals>.bar'
您说您不使用dill
的原因是
我看到了一个用例,莳萝可以作为pickle导入,这很酷,但是由于我将pickle和dill用于不同类型的序列化,所以在代码中造成了混乱。
但是您可以将pickle
序列化格式扩展为任何内部格式-json
,gzip
甚至dill
。你也可以吃蛋糕!
让我们尝试使用dill
,因为这很容易:
import pickle
import dill
class DillPickle:
def __init__(self, e):
self.e = e
def __getstate__(self):
return dill.dumps(self.e)
def __setstate__(self, state):
self.e = dill.loads(state)
Pickle通常通过递归腌制对象的__dict__
来序列化自定义类实例的状态。取消拾取后,它可以创建一个未初始化的实例,并使用保存的值更新其__dict__
。如果所有内容在整个过程中都是可腌制的,则可以使用。但是,如果不这样,则酸洗将失败(例如在lambda中)。但是pickle
模块提供了一个接口来覆盖此行为:__getstate__()
用于序列化对象的状态,而__setstate__()
用于从该值恢复它。如果__getstate__()
的返回值是可拾取的(并且实现了__setstate__()
),则此方法有效。在这种情况下,我们返回dill.dumps()
返回的可选取的字节串。
演示:
>>> pickle.dumps(DillPickle(lambda x, y: x+y))
b'\x80\x03c__main__\nDillPickle\nq\x00)\x81q\x01C\xe7\x80\x03cdill._dill\n_create_function\nq\x00(cdill._dill\n_load_type\nq\x01X\x08\x00\x00\x00CodeTypeq\x02\x85q\x03Rq\x04(K\x02K\x00K\x02K\x02KCC\x08|\x00|\x01\x17\x00S\x00q\x05N\x85q\x06)X\x01\x00\x00\x00xq\x07X\x01\x00\x00\x00yq\x08\x86q\tX\x1f\x00\x00\x00<ipython-input-18-48b9de2c6f55>q\nX\x08\x00\x00\x00<lambda>q\x0bK\x01C\x00q\x0c))tq\rRq\x0ec__builtin__\n__main__\nh\x0bNN}q\x0fNtq\x10Rq\x11.q\x02b.'
>>> pickle.loads(_).e('foo', 'bar')
'foobar'
请注意,我们加载了pickle
,而不是dill
!而且lambda 没有名称。当然,dill
必须对运行时可用,以便解开进程,但是DillPickle
类的其余部分也是如此,就像使用pickle
序列化的任何自定义类型一样。 dill
现在只是DillPickle
内部使用的实现细节。该界面为pickle
。
您甚至可以将其设为可调用的,因此无需自己添加.e
。
class DillPickleCallable(DillPickle):
def __call__(self, *args, **kwargs):
return self.e(*args, **kwargs)