【Python】解析Python中的装饰器

python中的函数也是对象,函数能够被看成变量传递。

装饰器在python中功能很是强大,装饰器容许对原有函数行为进行扩展,而不用硬编码的方式,它提供了一种面向切面的访问方式。python

 

装饰器

一个普通的装饰器通常是这样:app

import functools
def log(func):
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        print('call %s():' % func.__name__)
        print('args = {}'.format(*args))
        return func(*args, **kwargs)
    return wrapper

这样就定义了一个打印出方法名及其参数的装饰器。
调用之:函数

@log
def test(p):
    print(test.__name__ + " param: " + p)

test("I'm a param")

输出:编码

call test():
args = I'm a param
test param: I'm a param

装饰器在使用时,用了@语法,让人有些困扰。其实,装饰器只是个方法,与下面的调用方式没有区别:spa

def test(p):
    print(test.__name__ + " param: " + p)

wrapper = log(test)
wrapper("I'm a param")

@语法只是将函数传入装饰器函数,并没有神奇之处。
值得注意的是@functools.wraps(func),这是python提供的装饰器。它能把原函数的元信息拷贝到装饰器里面的 func 函数中。函数的元信息包括docstring、name、参数列表等等。能够尝试去除@functools.wraps(func),你会发现test.__name__的输出变成了wrapper。code

 

带参数的装饰器

装饰器容许传入参数,一个携带了参数的装饰器将有三层函数,以下所示:orm

import functools

def log_with_param(text):
    def decorator(func):
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            print('call %s():' % func.__name__)
            print('args = {}'.format(*args))
            print('log_param = {}'.format(text))
            return func(*args, **kwargs)

        return wrapper

    return decorator
    
@log_with_param("param")
def test_with_param(p):
    print(test_with_param.__name__)

看到这个代码是否是又有些疑问,内层的decorator函数的参数func是怎么传进去的?和上面通常的装饰器不大同样啊。
其实道理是同样的,将其@语法去除,恢复函数调用的形式一看就明白了:对象

# 传入装饰器的参数,并接收返回的decorator函数
decorator = log_with_param("param")
# 传入test_with_param函数
wrapper = decorator(test_with_param)
# 调用装饰器函数
wrapper("I'm a param")

输出结果与正常使用装饰器相同:blog

call test_with_param():
args = I'm a param
log_param = param
test_with_param

至此,装饰器这个有点费解的特性也没什么神秘了。
装饰器这一语法体现了Python中函数是第一公民,函数是对象、是变量,能够做为参数、能够是返回值,很是的灵活与强大。

get

原文连接:

https://www.jianshu.com/p/ee82b941772a
https://www.geeksforgeeks.org/decorators-in-python/

相关文章
相关标签/搜索