装饰器讲解


装饰器(Decorators)是 Python 的一个重要部分。简单地说:**他们是修改其他函数的功能的函数。**他们有助于让我们的代码更简短。装饰器让你在一个函数的前后去执行代码。

1. 装饰器基础

1.1. 函数、对象和变量

由于函数也是一个对象,而且函数对象可以被赋值给变量,所以,通过变量也能调用该函数。

def now():
    print("2020-01-30")
    
f = now    # 函数赋值给变量
f()        # 通过变量调用函数

1.2. 一个简单的装饰器

装饰器就是一个返回函数的高阶函数

def log(func):    # 接受函数作为参数
    def wrapper(*args, **kwargs):
        print("call %s" % func.__name__)
        return func(*args, **kwargs)
    return wrapper     # 返回一个函数

@log
def now():
    print("2020-01-30")
now()
out:
call now
2020-01-30

@log放在now函数上面,相当于执行了now = log(now)

1.3. 带参数的装饰器

如果装饰器需要传入参数,需要再封装一层。

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

@log('execute')   # 这里传入参数
def now():
    print("2020-01-30")
now()

此时,相当于now = log(‘execute’)(now)

1.4. 解决函数签名变化的问题

上面不带参数和带参数的装饰器中,通过调用now.__name__发现返回值为wrapper,这是因为now=log(now),now=log(‘execute’)(now)的返回值是wrapper函数,因此,有些依赖函数签名的代码执行会发生错误。
functools.wraps可以解决这个问题。

import functools

def log(func):    # 接受函数作为参数
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        print("call %s" % func.__name__)
        return func(*args, **kwargs)
    return wrapper     # 返回一个函数

@log
def now():
    print("2020-01-30")
now()

now.__name__
import functools
def log(text):
    def decorator(func):
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            print("%s, %s" % (text, func.__name__))
            return func(*args, **kwargs)
        return wrapper 
    return decorator

@log('execute')
def now():
    print("2020-01-30")
now()
now.__name__

functools.wraps 旨在消除装饰器对原函数造成的影响,即对原函数的相关属性进行拷贝,已达到装饰器不修改原函数的目的。

2. 参考

  1. 廖雪峰装饰器讲解here
  2. functools.wraps()讲解here
发布了24 篇原创文章 · 获赞 3 · 访问量 4605

猜你喜欢

转载自blog.csdn.net/qq_31699845/article/details/104112428