Как преобразовать объект `lambda` в объект`function` в Python?
Я имел дело с ошибками, касающимися lambda
функции и их неспособность быть pickled
, Я часто использую 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 ответов
pickle
не сохраняет объект кода, только его имя. Однако присвоения функции имени недостаточно, чтобы сделать ее маринованной, потому чтоunpickle
десериализует его, импортировав имя. Естественно, это означает, что он должен быть импортирован средой выполнения unpickling. Функцииdef
ed с именами по этой причине все еще может не засолиться. Так что даже если бы вы могли преобразовать свои лямбды в именованные функции, это все равно не сработало бы:
>>> 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
Формат сериализации расширяется до любого внутреннего формата, который вам нравится -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__
с сохраненными значениями. Если все его содержимое можно мариновать, это работает. Но в противном случае (как в случае с лямбдами) травление не удастся. Но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
! А у лямбды нет имени. Конечно,dill
должен быть доступен для среды выполнения, чтобы распаковывать, но то же самое делает и остальная часть DillPickle
класс, как и для любого настраиваемого типа, сериализованного с помощью pickle
. dill
теперь просто деталь реализации, используемая внутри DillPickle
. Интерфейсpickle
.
Вы даже можете сделать его вызываемым, поэтому вам не нужно добавлять .e
сами.
class DillPickleCallable(DillPickle):
def __call__(self, *args, **kwargs):
return self.e(*args, **kwargs)