Python装饰器保持签名和用户定义的属性

bru*_*yne 8 python ipython python-2.7 python-decorators

我有我的简单装饰器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'
Run Code Online (Sandbox Code Playgroud)

直到这里工作,但我看不到功能的实际签名.

my_func?
Signature: my_func(*args, **kwargs)
Docstring: <no docstring>
File:      ~/<ipython-input-2-e4c91999ef66>
Type:      function
Run Code Online (Sandbox Code Playgroud)

如果我用python's装饰我的装饰器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_'
Run Code Online (Sandbox Code Playgroud)

我如何在python2.7中同时拥有这两个?

pla*_*aes 11

对于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_)
Run Code Online (Sandbox Code Playgroud)


Tar*_*ani 5

工作

@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_)
Run Code Online (Sandbox Code Playgroud)

然后当你测试它的工作原理

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'
Run Code Online (Sandbox Code Playgroud)