`

Python装饰器

 
阅读更多

原创转载请注明出处:http://agilestyle.iteye.com/blog/2330385

 

通过__name__属性获取函数的名字

def hello_world():
    print('Hello World')


f = hello_world

# hello_world
print(hello_world.__name__)
# hello_world
print(f.__name__)

 

 

接下来,我们为hello_world函数做一个增强,但是并不改变原函数的定义,而是在代码运行期间动态增加额外的功能,在Python中成为装饰器(Decorator),就好比Spring的AOP。

def log(func):
    def wrapper(*args, **kw):
        print('call %s():' % func.__name__)
        return func(*args, **kw)

    return wrapper


@log
def hello_world():
    print('Hello World')


hello_world()
# wrapper
print(hello_world.__name__)

Console Output


Note:

由于log()是一个decorator,返回一个函数,所以原来的hello_world()函数仍然存在,于是调用hello_world()将执行新函数,即在log()函数中返回的wrapper()函数。

wrapper()函数的参数定义是(*args, **kw),因此,wrapper()函数可以接受任意参数的调用。在wrapper()函数内,首先打印日志,再紧接着调用原始函数。 

 

decorator本身需要传入参数,比如自定义log的文本

def log(text):
    def decorator(func):
        def wrapper(*args, **kw):
            print('%s %s()' % (text, func.__name__))
            return func(*args, **kw)

        return wrapper

    return decorator


@log('invoke')
def hello_world():
    print('Hello World')


hello_world()
# wrapper
print(hello_world.__name__)

Console Output


Note: 

以上两种decorator的定义都没有问题,可函数也是对象,有__name__等属性,但是经过decorator装饰之后的函数,它们的__name__已经从原来的'hello_world'变成了'wrapper',因为返回的那个wrapper()函数名字就是'wrapper',所以,需要把原始函数的__name__等属性复制到wrapper()函数中,否则,有些依赖函数签名的代码执行就会出错。

 

可以编写这样的代码解决问题:

wrapper.__name__ = func.__name__

但是并不需要,Python内置的functools.wraps就是干这个事的,所以一个完整的decorator的写法如下:

from functools import wraps


def log(func):
    @wraps(func)
    def wrapper(*args, **kw):
        print('call %s():' % func.__name__)
        return func(*args, **kw)

    return wrapper


@log
def hello_world():
    print('Hello World')


hello_world()
# hello_world
print(hello_world.__name__)

 Console Output


 

针对带参数的decorator

from functools import wraps


def log(text):
    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kw):
            print('%s %s():' % (text, func.__name__))
            return func(*args, **kw)

        return wrapper

    return decorator


@log('invoke')
def hello_world():
    print('Hello World')


hello_world()
# hello_world
print(hello_world.__name__)

Console Output 


 

 

 

  • 大小: 7.7 KB
  • 大小: 6.6 KB
  • 大小: 6.6 KB
  • 大小: 6.7 KB
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics