我有我的简单装饰者my_decorator
装饰my_func
。
def my_decorator(func):
def wrapper(*args, **kwargs):
return func(*args, **kwargs)
wrapper._decorator_name_ = 'my_decorator'
return wrapper
@my_decorator
def my_func(x):
print('hello %s'%x)
my_func._decorator_name_
'my_decorator'
直到这里工作,但我看不到功能的实际签名。
my_func?
Signature: my_func(*args, **kwargs)
Docstring: <no docstring>
File: ~/<ipython-input-2-e4c91999ef66>
Type: function
如果我用python的decorator.decorator
装饰我的装饰器,我可以看到我的函数的签名但我不能拥有我定义的新属性。
import decorator
@decorator.decorator
def my_decorator(func):
def wrapper(*args, **kwargs):
return func(*args, **kwargs)
wrapper._decorator_name_ = 'my_decorator'
return wrapper
@my_decorator
def my_func(x):
print('hello %s'%x)
my_func?
Signature: my_func(x)
Docstring: <no docstring>
File: ~/<ipython-input-8-934f46134434>
Type: function
my_func._decorator_name_
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-10-7e3ef4ebfc8b> in <module>()
----> 1 my_func._decorator_name_
AttributeError: 'function' object has no attribute '_decorator_name_'
我如何在python2.7中同时拥有这两个?
对于Python 3,在标准库中使用functools.wraps:
from functools import wraps
def my_decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
return func(*args, **kwargs)
wrapper._decorator_name_ = 'my_decorator'
return wrapper
@my_decorator
def my_func(x):
print('hello %s'%x)
print(my_func._decorator_name_)
@decorator.decorator
返回一个函数,该函数将另一个函数作为输入。在您的情况下,您需要返回函数的属性。
要使它在Python 2.7上运行,您只需要进行一些调整
import decorator
def my_dec2(func):
@decorator.decorator
def my_decorator(func, *args, **kwargs):
print("this was called")
return func(*args, **kwargs)
test = my_decorator(func)
test._decorator_name_ = "my_decorator"
return test
@my_dec2
def my_func(x):
print('hello %s'%x)
my_func(2)
print(my_func._decorator_name_)
然后当你测试它的工作原理
In [1]: my_func?
Signature: my_func(x)
Docstring: <no docstring>
File: ~/Desktop/payu/projects/decotest/decos.py
Type: function
In [2]: my_func._decorator_name_
Out[2]: 'my_decorator'
如果您想以某种方式改变函数的行为,则只需要定义wrapper
函数。因此,如果您真的只想在不更改其行为的情况下为函数添加某些属性,则可以执行以下操作。
def my_decorator(func):
func._decorator_name_ = 'my_decorator'
return func
在更复杂的情况下,你需要有一个wrapper
,我建议遵循accepted answer for this question,它解释了如何创建一个与另一个相同的功能,但具有自定义签名。使用inspect.getargspec
你可以从my_func
恢复签名并将其转换为你的wrapper
。
正如其他人指出的那样,你似乎没有正确使用decorator
。
或者,您可以使用我的库makefun
来创建保留签名的包装器,它依赖于与decorator
相同的技巧来保留签名,但更侧重于动态函数创建,并且更通用(您可以更改签名):
from makefun import wraps
def my_decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
return func(*args, **kwargs)
wrapper._decorator_name_ = 'my_decorator'
return wrapper
您可以检查它是否按预期工作:
@my_decorator
def my_func(x):
"""my function"""
print('hello %s' % x)
assert my_func._decorator_name_ == 'my_decorator'
help(my_func)
对于它的价值,如果你希望稍后向装饰器添加可选参数而不使代码看起来更复杂,那么看看decopatch
。例如,如果您希望_decorator_name_
成为装饰器的可选参数:
from decopatch import function_decorator, DECORATED
from makefun import wraps
@function_decorator
def my_decorator(name='my_decorator', func=DECORATED):
@wraps(func)
def wrapper(*args, **kwargs):
return func(*args, **kwargs)
wrapper._decorator_name_ = name
return wrapper