简体   繁体   English

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

[英]How to convert `lambda` object to `function` object for pickling in Python?

I've been dealing with errors regarding lambda functions and their inability to be pickled .我一直在处理有关lambda函数及其无法被pickled I often use lambda functions on the fly as one time use functions and it vastly decreases my workflow productivity when I have to individually recreate simple lambda functions in functional form for use with pickling.我经常在运行中使用lambda函数作为一次性使用函数,当我必须以函数形式单独重新创建简单的 lambda 函数以用于酸洗时,它会大大降低我的工作流程生产力。

Is there a way to convert a lambda and all of its arguments into a function object in Python 3.6.1 ?有没有办法在Python 3.6.1中将lambda及其所有参数转换为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

pickle does not save the code object, just its name. pickle不保存代码对象,只保存它的名字。 However, giving a function a name is not enough to make it pickleable, because unpickle deserializes it by importing the name.然而,给一个函数一个名字并不足以使它成为可腌制的,因为unpickle通过导入名字来反序列化它。 Naturally, this means it must be importable by the unpickling runtime.自然地,这意味着它必须可以由 unpickling 运行时导入 Functions def ed with names can still fail to pickle for this reason.功能def与名编仍可能失败咸菜这个原因。 So even if you could convert your lambdas to named functions, that still wouldn't work:因此,即使您可以将 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'

You say your reason for not using dill instead is你说你不使用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.我见过一个用例,其中 dill 可以作为 pickle 导入,这很酷,但在代码中变得混乱,因为我将 pickle 和 dill 用于不同类型的序列化。

But the pickle serialization format is extensible to any internal format you please — json , gzip , even dill .但是pickle序列化格式可以扩展为您喜欢的任何内部格式—— jsongzip ,甚至dill You can have your cake and eat it too!你可以吃蛋糕也可以吃!

Let's try it with dill , because that makes it easy:让我们用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 normally serializes the state of custom class instances by recursively pickling the object's __dict__ . Pickle 通常通过递归酸洗对象的__dict__来序列化自定义类实例的状态。 On unpickling, it can then make an uninitialized instance and update its __dict__ with the saved values.在 unpickling 时,它可以创建一个未初始化的实例并使用保存的值更新其__dict__ If all of its contents are pickleable all the way down, this works.如果它的所有内容一直都是可腌制的,则此方法有效。 But if not, (as in the case of the lambdas) pickling would fail.但如果没有,(如 lambdas 的情况)酸洗将失败。 But the pickle module provides an interface to override this behavior: __getstate__() for serializing the object's state, and __setstate__() for restoring it from that value.但是pickle模块提供了一个接口来覆盖此行为: __getstate__()用于序列化对象的状态,以及__setstate__()用于从该值恢复它。 If the return value of __getstate__() is picklable (and __setstate__() is implemented), this works.如果__getstate__()的返回值是可__getstate__() (并且__setstate__()已实现),则此方法有效。 In this case, we return the picklable bytestring returned by dill.dumps() .在这种情况下,我们返回dill.dumps()返回的可dill.dumps()字节dill.dumps()

Demonstration:示范:

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

Notice that we loaded it with pickle , not dill !请注意,我们为它加载了pickle ,而不是dill And the lambda does not have a name .并且 lambda没有 name Of course, dill must be available to the runtime in order to unpickle, but so does the rest of the DillPickle class, just like for any custom type serialized with pickle .当然, dill必须对运行时可用才能DillPickle ,但DillPickle类的其余部分也是DillPickle ,就像任何用pickle序列化的自定义类型一样。 dill is now a mere implementation detail used internally by DillPickle . dill现在只是DillPickle内部使用的一个实现细节。 The interface is pickle .接口是pickle

You could even make it a callable, so you don't need to add the .e yourself.您甚至可以将其设置为可调用的,因此您无需自己添加.e

class DillPickleCallable(DillPickle):
    def __call__(self, *args, **kwargs):
        return self.e(*args, **kwargs)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM