我有一些函数,在正常情况下,用用户输入提供的参数调用。但是,使用某些参数调用这些函数是有效的,这些参数是在运行时根据某些系统状态确定的。
我希望用户能够选择指示我的程序使用所有有效输入调用这些函数并返回每个调用的结果。我认为一个装饰器可以像激活开关一样工作,它有另一个装饰器,它指示使用哪个参数系列会很好。
此外,我需要来保留功能签名和元数据。这对我的计划的运作至关重要。
这是我尝试过的,但它不起作用。它基于this example。
>>> from decorator import decorator
>>> def the_list():
... return ["foo", "bar", "baz"]
...
>>> import itertools
>>> @decorator
... def do_all(func):
... # this will do nothing (besides wrap in a tuple) unless func is decorated with @gets_arg_from
... if hasattr(func, 'get_from'):
... return tuple(func(*args) for args in itertools.product(*(list_fun() for list_fun in func.get_from)))
... else:
... return (func(),)
...
>>> def gets_arg_from(*list_funcs):
... # this will do nothing to func unless decorated with @do_all
... def gets_arg_from(func, *args, **kwargs):
... func.get_from = list_funcs
... return func(*args, **kwargs)
... return decorator(gets_arg_from)
...
>>> @gets_arg_from(the_list)
... def print_func(word):
... # this will print its argument unless decorated with @do_all
... # at that point it will print every element returned by the_list()
... print word
...
>>> print_func("foo")
foo
>>> all = decorator(do_all, print_func)
>>> all()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: print_func() takes exactly 1 argument (0 given)
>>> print_func.get_from
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'function' object has no attribute 'get_from'
我的期望是:
>>> all()
("foo", "bar", "baz")
我注意到的是错误的:
gets_arg_from
未将get_from
属性添加到func
。@gets_arg_from(the_list)
的一些事情是错误的。它认为我试图通过两个论点(但为什么这仍然是一个问题?)至于我的动机,我想到装饰器,因为这些例程实际上有数百个,它们的实现细节(以及它们的功能正确性)经常变化,我不想使用inspect
基于他们的参数名称来推理做什么,我也不想为每个有意义的函数硬编码do_all
功能。类方法可能有效,但出于我的目的,它们在语义上有所设计。此外,为了其他可能需要维护我的代码的人,我认为要求他们应用装饰器更容易,而不是担心其余的而不是使用某些参数名称或将函数放在某个类或随你。我意识到这个问题可能听起来很奇怪,所以我认为这个脚注可能会让我看起来不像疯子。
答案 0 :(得分:1)
这不是你想做的事吗?
import functools
from itertools import product
def the_list():
return ["foo", "bar", "baz"]
def do_all(func):
if hasattr(func, 'get_from'):
@functools.wraps(func)
def wrapper(*args, **kwargs):
return tuple(func(*args) for args in
product(*(lf() for lf in func.get_from)))
return wrapper
return func
def gets_arg_from(*list_funcs):
def decorator(func):
func.get_from = list_funcs
return func
return decorator
@gets_arg_from(the_list)
def print_func(word):
return word
print print_func('foo')
all = do_all(print_func)
print all()
编辑解释
这两个代码段是相同的:
@deco
def func(...):
some code
与
相同func = deco(lambda ...: some code)
@something只是函数调用和匿名函数创建的语法糖...
我将逐步解释下一个代码安息中发生的事情:
@gets_arg_from(the_list)
def print_func(word):
return word
首先,Python创建一个接收参数word
的函数,并且有一个只返回此word
的函数(或函数体做的任何事情)
然后调用函数get_arg_from
并将the_list
作为参数传递给它
get_arg_from
创建一个decorator
函数并将其返回
从decorator
返回的get_arg_from
函数被调用(这是语法糖的东西)作为参数传递func
在步骤1中创建的无穷函数。 / p>
decorator
只是将list_funcs
元组分配给匿名函数的get_from
属性并返回无穷大的函数
decorator
函数的返回值已分配给变量print_func
可以通过以下方式实现类似的效果:
def __anonimous(word):
return word
__decorator = gets_arg_from(the_list)
print_func = __decorator(__anonimous)
所以基本上gets_arg_from
不是装饰器,它是一个返回装饰器的函数。
do_all
是装饰器,它接收函数作为参数,并返回原始函数(如果函数没有属性{{1} }}或get_from
函数替换原始函数(如果它具有wrapper
属性)。
您可以找到更多示例here。