以下是使用functools.wrap
的另一种方法,至少在Python 3中保留了签名和文档字符串。诀窍是在从未被调用的虚拟函数中创建签名和文档。以下是几个示例。
基本示例
import functools
def wrapper(f):
@functools.wraps(f)
def template(common_exposed_arg, *other_args, common_exposed_kwarg=None, **other_kwargs):
print("\ninside template.")
print("common_exposed_arg: ", common_exposed_arg, ", common_exposed_kwarg: ", common_exposed_kwarg)
print("other_args: ", other_args, ", other_kwargs: ", other_kwargs)
return template
@wrapper
def exposed_func_1(common_exposed_arg, other_exposed_arg, common_exposed_kwarg=None):
"""exposed_func_1 docstring: this dummy function exposes the right signature"""
print("this won't get printed")
@wrapper
def exposed_func_2(common_exposed_arg, common_exposed_kwarg=None, other_exposed_kwarg=None):
"""exposed_func_2 docstring"""
pass
exposed_func_1(10, -1, common_exposed_kwarg='one')
exposed_func_2(20, common_exposed_kwarg='two', other_exposed_kwarg='done')
print("\n" + exposed_func_1.__name__)
print(exposed_func_1.__doc__)
结果是:
>> inside template.
>> common_exposed_arg: 10 , common_exposed_kwarg: one
>> other_args: (-1,) , other_kwargs: {}
>>
>> inside template.
>> common_exposed_arg: 20 , common_exposed_kwarg: two
>> other_args: () , other_kwargs: {'other_exposed_kwarg': 'done'}
>>
>> exposed_func_1
>> exposed_func_1 docstring: this dummy function exposes the right signature
调用
inspect.signature(exposed_func_1).parameters
可以返回所需的签名。但是,使用
inspect.getfullargspec(exposed_func_1)
仍然返回
template
的签名。至少,如果您在
template
的定义中放置任何所有要创建的函数的公共参数,那么这些参数将出现。
如果由于某种原因这是个坏主意,请告诉我!
更复杂的例子
您可以比这更复杂,通过在更多包装器中添加更多层,并在内部函数中定义更多不同的行为:
import functools
def wrapper(inner_func, outer_arg, outer_kwarg=None):
def wrapped_func(f):
@functools.wraps(f)
def template(common_exposed_arg, *other_args, common_exposed_kwarg=None, **other_kwargs):
print("\nstart of template.")
print("outer_arg: ", outer_arg, " outer_kwarg: ", outer_kwarg)
inner_arg = outer_arg * 10 + common_exposed_arg
inner_func(inner_arg, *other_args, common_exposed_kwarg=common_exposed_kwarg, **other_kwargs)
print("template done")
return template
return wrapped_func
def inner_fcn_1(hidden_arg, exposed_arg, common_exposed_kwarg=None):
print("inner_fcn, hidden_arg: ", hidden_arg, ", exposed_arg: ", exposed_arg, ", common_exposed_kwarg: ", common_exposed_kwarg)
def inner_fcn_2(hidden_arg, common_exposed_kwarg=None, other_exposed_kwarg=None):
print("inner_fcn_2, hidden_arg: ", hidden_arg, ", common_exposed_kwarg: ", common_exposed_kwarg, ", other_exposed_kwarg: ", other_exposed_kwarg)
@wrapper(inner_fcn_1, 1)
def exposed_function_1(common_exposed_arg, other_exposed_arg, common_exposed_kwarg=None):
"""exposed_function_1 docstring: this dummy function exposes the right signature """
print("this won't get printed")
@wrapper(inner_fcn_2, 2, outer_kwarg="outer")
def exposed_function_2(common_exposed_arg, common_exposed_kwarg=None, other_exposed_kwarg=None):
""" exposed_2 doc """
pass
这段话有点啰嗦,但是它想表达的是,在使用这种方法来创建函数时,你(程序员)的动态输入有很大的灵活性,所以在使用功能的用户暴露的输入处也同样具有灵活性。