Input/output pickle 函数结果的装饰器
Input/output decorator to pickle function result
给定一个带有参数 a
和另外两个参数(pickle_from
、pickle_to
)的函数,我想:
- 如果
pickle_from
不是None
,则加载并return 位于pickle_from
的pickled 对象。如果它是 None
,计算 a
和 return 的一些函数。
- 如果
pickle_to
不是 None
,则将上面的结果转储到 pickle_to
。
使用单个函数,这很简单。如果 pickle_from
不为 null,则该函数只加载腌制结果并 returns 它。否则,它会使用 a
执行一些耗时的计算,将其转储到 pickle_to
,然后 return 计算结果。
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
这可能吗?关于装饰器的一些事情让我脑袋爆炸,所以我会礼貌地拒绝post这里"what I have tried."
鉴于您的用例,我认为仅使用通用包装器会更清楚:
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")
这避免了在您要使用此功能的任何地方都必须添加装饰器,并且实际上适用于您的代码或其他任何可调用对象(不仅仅是函数)。
这个装饰器需要一点反省。具体来说,我利用 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
给定一个带有参数 a
和另外两个参数(pickle_from
、pickle_to
)的函数,我想:
- 如果
pickle_from
不是None
,则加载并return 位于pickle_from
的pickled 对象。如果它是None
,计算a
和 return 的一些函数。 - 如果
pickle_to
不是None
,则将上面的结果转储到pickle_to
。
使用单个函数,这很简单。如果 pickle_from
不为 null,则该函数只加载腌制结果并 returns 它。否则,它会使用 a
执行一些耗时的计算,将其转储到 pickle_to
,然后 return 计算结果。
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
这可能吗?关于装饰器的一些事情让我脑袋爆炸,所以我会礼貌地拒绝post这里"what I have tried."
鉴于您的用例,我认为仅使用通用包装器会更清楚:
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")
这避免了在您要使用此功能的任何地方都必须添加装饰器,并且实际上适用于您的代码或其他任何可调用对象(不仅仅是函数)。
这个装饰器需要一点反省。具体来说,我利用 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