给定一个带参数a
的函数和另外两个参数(pickle_from
,pickle_to
),我想:
pickle_from
不是pickle_from
,请加载并返回位于None
的腌制对象。如果是None
,请计算a
的某些函数并将其返回。pickle_to
不是pickle_to
,则将上述结果转储到None
。使用单一功能,这很简单。如果pickle_from
不为null,则该函数仅加载pickle结果并返回它。否则,它会使用a
执行一些时间密集型计算,将其转储到pickle_to
,并返回计算结果。
try:
import cPickle as pickle
except:
import pickle
def somefunc(a, pickle_from=None, pickle_to=None):
if pickle_from:
with open(pickle_from + '.pickle', 'rb') as f
res = pickle.load(f)
else:
# Re-calcualte some time-intensive func call
res = a ** 2
if pickle_to:
# Update pickled data with newly calculated `res`
with open(pickle_to + '.pickle', 'wb') as f:
pickle.dump(res, f)
return res
我的问题是关于如何构建装饰器,以便此过程可以围绕类似于somefunc
的多个函数形成一个shell,从而减少过程中的源代码。
我希望能够写出类似的内容:
@pickle_option
def somefunc(a, pickle_from=None, pickle_to=None)
# or do params need to be in the decorator call?
# remember, "the files are in the computer"
res = a ** 2
return res
这可能吗?关于装饰器的东西会让我的脑袋爆炸,所以我会礼貌地拒绝在这里发布“我尝试过的东西。”
答案 0 :(得分:2)
这个装饰者需要一点内省。具体来说,我已使用inspect.Signature
来提取pickle_from
和pickle_to
参数。
除此之外,它是一个非常简单的装饰器:它保留对装饰函数的引用,并在必要时调用它。
import inspect
from functools import wraps
def pickle_option(func):
sig = inspect.signature(func)
@wraps(func)
def wrapper(*args, **kwargs):
# get the value of the pickle_from and pickle_to parameters
# introspection magic, don't worry about it or read the docs
bound_args = sig.bind(*args, **kwargs)
pickle_from = bound_args.arguments.get('pickle_from', \
sig.parameters['pickle_from'].default)
pickle_to = bound_args.arguments.get('pickle_to', \
sig.parameters['pickle_to'].default)
if pickle_from:
with open(pickle_from + '.pickle', 'rb') as f:
result = pickle.load(f)
else:
result = func(*args, **kwargs)
if pickle_to:
with open(pickle_to + '.pickle', 'wb') as f:
pickle.dump(result, f)
return result
return wrapper
答案 1 :(得分:1)
鉴于您的用例,我认为仅使用通用包装器会更清楚:
def pickle_call(fun, *args, pickle_from=None, pickle_to=None, **kwargs):
if pickle_from:
with open(pickle_from + '.pickle', 'rb') as f
res = pickle.load(f)
else:
res = fun(*args, **kwargs)
if pickle_to:
# Update pickled data with newly calculated `res`
with open(pickle_to + '.pickle', 'wb') as f:
pickle.dump(res, f)
return res
然后你就像使用它一样:
res = pickle_call(somefunc, a, pickle_from="from", pickle_to="to")
这样可以避免在任何想要使用此功能的地方添加装饰器,并且实际上可以使用代码中的任何可调用(不仅仅是函数)。