我按下面的代码编写get_function_arg_data(func)
来获取函数func
的参数信息:
def get_function_arg_data(func):
import inspect
func_data = inspect.getargspec(func)
args_name = func_data.args #func argument list
args_default = func_data.defaults #funcargument default data list
return args_name, args_default
def showduration(user_function):
''' show time duration decorator'''
import time
def wrapped_f(*args, **kwargs):
t1 = time.clock()
result = user_function(*args, **kwargs)
print "%s()_Time: %0.5f"%(user_function.__name__, time.clock()-t1)
return result
return wrapped_f
def foo(para1, para2=5, para3=7):
for i in range(1000):
s = para1+para2+para3
return s
@showduration
def bar(para1, para2, para3):
for i in range(1000):
s=para1+para2+para3
return s
print get_function_arg_data(foo)
bar(1,2,3)
print get_function_arg_data(bar)
>>>
(['para1', 'para2', 'para3'], (5, 7))
bar()_Time: 0.00012
([], None)
>>>
get_function_arg_data()
适用于foo
,不适用于bar
,因为条形图由装饰器@showduration
修饰。我的问题是如何穿透装饰器来获取底层函数的信息(参数列表和默认值)?
感谢您的提示。
答案 0 :(得分:1)
假设您已经安装了Michele Simionato的decorator模块,您可以对showduration
装饰器进行一些微小的修改,并对其中定义的嵌套wrapped_f()
函数进行修改。所以后者符合模块的decorator.decorator()
函数所期望的签名:
import decorator
def showduration(user_function):
''' show time duration decorator'''
import time
def wrapped_f(user_function, *args, **kwargs):
t1 = time.clock()
result = user_function(*args, **kwargs)
print "%s()_Time: %0.5f"%(user_function.__name__, time.clock()-t1)
return result
return decorator.decorator(wrapped_f, user_function)
然而,该模块真的很闪耀,因为它可以让你将上面的样板材减少到只有:
import decorator
@decorator.decorator
def showduration(user_function, *args, **kwargs):
import time
t1 = time.clock()
result = user_function(*args, **kwargs)
print "%s()_Time: %0.5f"%(user_function.__name__, time.clock()-t1)
return result
使用上述任一组更改,您的示例代码将输出:
(['para1', 'para2', 'para3'], (5, 7))
bar()_Time: 0.00026
(['para1', 'para2', 'para3'], None)
答案 1 :(得分:1)
我认为没有,或者至少知道任何“渗透”装饰函数和获取基础函数信息的一般方法,因为Python的函数修饰概念是所以一般 - 如果事实上,一般来说,没有任何东西需要或保证原始函数将被调用(尽管通常是这种情况)。
因此,一个更实际的问题是:我如何编写自己的装饰器,这将允许我检查底层函数的参数信息?
之前建议的一个简单方法是使用Michele Simionato的decorator模块(以及与之兼容的写装饰器)。
执行此操作的不太强大但非常简单的方法是根据您问题中的代码执行下面显示的操作:
def get_function_arg_data(func):
import inspect
func = getattr(func, '_original_f', func) # use saved original if decorated
func_data = inspect.getargspec(func)
args_name = func_data.args #func argument list
args_default = func_data.defaults #funcargument default data list
return args_name, args_default
def showduration(user_function):
'''show time duration decorator'''
import time
def wrapped_f(*args, **kwargs):
t1 = time.clock()
result = user_function(*args, **kwargs)
print "%s()_Time: %0.5f"%(user_function.__name__, time.clock()-t1)
return result
wrapped_f._original_f = user_function # save original function
return wrapped_f
def foo(para1, para2=5, para3=7):
for i in range(1000):
s = para1+para2+para3
return s
@showduration
def bar(para1, para2, para3):
for i in range(1000):
s=para1+para2+para3
return s
print 'get_function_arg_data(foo):', get_function_arg_data(foo)
print 'get_function_arg_data(bar):', get_function_arg_data(bar)
所有修改都涉及将原始函数保存在名为_original_f
的属性中,该属性添加了装饰器返回的包装函数。然后get_function_arg_data()
函数只检查此属性并根据其值返回信息,而不是传递给它的修饰函数。
虽然这种方法不适用于任何修饰函数,但只有那些已经添加了特殊属性的函数,它与Python 2& 3。
显示的代码产生的输出:
get_function_arg_data(foo): (['para1', 'para2', 'para3'], (5, 7))
get_function_arg_data(bar): (['para1', 'para2', 'para3'], None)