Маринованные обернутые частичные функции
Я пытаюсь создать подобрать декоратор с использованием частичных функций. Тем не менее, я продолжаю получать ошибки травления при попытке сделать это.
Первый наивный пример выглядит следующим образом:
def decorator(func):
def wrapper(**kwargs):
return partial(func, **kwargs)
return wrapper
@decorator
def decorated(x, y=1, z=2):
return x+y+z
y5 = decorated(y=5)
pickle.dumps(y5)
куда partial
взят из functools
,
Чуть менее наивная попытка включает добавление @wraps
на одну строку выше def wrapper
, Это не помогает
Я не уверен, что понимаю, как работает травление.
1 ответ
Проблема в вашем декораторе, а не с частичным. Частичный объект должен просто мариновать:
>>> from pickle import *
>>> from functools import *
>>> f = partial(pow, 2)
>>> p = dumps(f)
>>> g = loads(p)
>>> g(5)
32
Итак, эта проблема с вашим кодом находится в декораторе. Это не сохранение имени исходной функции. Попробуйте это вместо этого:
import pickle
from functools import *
def decorator(func):
def wrapper(**kwargs):
return partial(func, **kwargs)
return wrapper
def decorated(x, y=1, z=2):
return x+y+z
dd = decorator(decorated)
y5 = dd(y=5)
pickle.dumps(y5)
Модификация для использования dd
должен позволить логике pickle обнаруживать основную функцию по ее имени. Так работают соленья.
Чтобы увидеть имя функции в pickle, посмотрите на вывод dumps:
>>> print pickle.dumps(y5)
cfunctools
partial
p0
(c__main__
decorated
p1
tp2
Rp3
(g1
(t(dp4
S'y'
p5
I5
sNtp6
b.
Слово "украшенный" должно быть найдено, соответствовать основной функции и не быть скрытым декоратором. Помните, что когда функции подвергаются травлению, сохраняются только их имена. Фактическое содержание функции не в рассоле.
Есть некоторые обходные пути, но они не красивые. Вы можете использовать __setstate__() для сохранения как имени функции, так и ее исходного кода. Затем добавьте метод __getstate__(), чтобы восстановить функцию, выполнив ее источник.
Кроме того, вы можете извлечь байтовые коды из объекта объекта функции и сохранить их. После восстановления скомпилируйте объект кода и выполните его.
Короче говоря, ваша цель использования декоратора с нотацией @ напрямую расходится с тем, как работает выбор функций. Чтобы достичь своей цели, вам нужно настроить функцию выбора функции, чтобы сохранить то, что делает функция, а не только ее имя.