如何在Python中将'lambda'对象转换为'function'对象以进行酸洗?

2024-09-27 23:17:00 发布

您现在位置:Python中文网/ 问答频道 /正文

我一直在处理关于lambda函数的错误,以及它们无法成为pickled。我经常动态地使用lambda函数作为一次性使用函数,当我必须单独以函数形式重新创建简单的lambda函数以用于酸洗时,这会大大降低我的工作效率

是否有方法将lambda及其所有参数转换为Python 3.6.1中的function对象?

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

Tags: ofthelambda函数inputstringdefsplit
1条回答
网友
1楼 · 发布于 2024-09-27 23:17:00

pickle不保存代码对象,只保存其名称。但是,给函数一个名称不足以使其可pickle,因为unpickle通过导入名称对其进行反序列化。当然,这意味着它必须由取消勾选运行时导入。由于这个原因,带有名称的函数def仍可能无法pickle。因此,即使您可以将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的原因是

I've seen a use case where dill can be imported as pickle which is pretty cool but gets confusing in the code since I used pickle and dill for different types of serialization.

但是pickle序列化格式是可扩展的到任何您喜欢的内部格式-jsongzip,甚至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通常通过递归地Pickle对象的__dict__来序列化自定义类实例的状态。在取消勾选时,它可以创建一个未初始化的实例,并用保存的值更新其__dict__。如果它的所有内容物都可以一直腌制下去,这就行了。但如果不是这样,(就像兰姆达斯的情况一样)酸洗就会失败。但是pickle模块提供了一个接口来重写此行为:__getstate__()用于序列化对象的状态,以及__setstate__()用于从该值还原对象。如果__getstate__()的返回值是可拾取的(并且__setstate__()已实现),则此操作有效。在本例中,我们返回由dill.dumps()返回的pickable bytestring

演示:

>>> 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)

相关问题 更多 >

    热门问题