【Python 进阶】装饰器

Python 装饰器

什么是装饰器

装饰器就是把一个函数当参数传到另一个函数(也可以是可迭代对象 callable)中,然后再回调, @ 是其语法糖

常见的四种形态的装饰器

1. 不带参数的装饰器

def logger(func):
    def wrapper(*args, **kwargs):
        print(f'prepare to run {func.__name__}')
        func(*args, **kwargs)
        print('finished...')

    return wrapper


@logger
def add(x, y):
    print(f'{x} + {y} = {x+y}')


add(1, 2)

2. 带参数的装饰器

def logger(level='INFO'):
    def wrapper(func):
        def handle(*args, **kwargs):
            print(f'{level}: prepare to run {func.__name__}')
            func(*args, **kwargs)
            print('finished...')
        return handle
    return wrapper


@logger('ERROR')
def add(x, y):
    print(f'{x} + {y} = {x+y}')

add(1, 2)

3. 不带参数的类装饰器

不带参数时,初始化的参数为被装饰函数,即两层结构。

class logger(object):
    def __init__(self, func):
        self.func = func

    def __call__(self, *args, **kwargs):
        print(f'{self.level}: prepare to run {func.__name__}')
        return self.func(*args, **kwargs)


@logger
def add(x, y):
    print(f'{x} + {y} = {x+y}')

add(1, 2)

4. 带参数的类装饰器

带参数时,初始化的参数为装饰函数的参数,即三层结构。

class logger(object):
    def __init__(self, level="INFO"):
        self.level = level

    def __call__(self, func):
        def wrapper(*args, **kwargs):
            print(f'{self.level}: prepare to run {func.__name__}')
            return func(*args, **kwargs)

        return wrapper

    
@logger('ERROR')
def add(x, y):
    print(f'{x} + {y} = {x+y}')

add(1, 2)

使用装饰器的注意事项

1. 使用 functools 中的 wraps

保持被装饰函数签名, 否则签名为装饰器对象

from functools import wraps

def wrapper(func):
    @wraps(func) 
    def handle():
        pass
    return handle

@wrapper
def wrapped():
    pass

print(wrapped.__name__)
# wrapped

2. 装饰顺序

执行顺序: wrapper1 > wrapper2 (wrapper1 装饰 wrapper2, wrapper2 装饰 func)

@wrapper1
@wrapper2
def func():
    pass

3. 闭包

def counter(func):
    def wrapper(*args, **kwargs):
        wrapper.count = wrapper.count + 1
        res = func(*args, **kwargs)
        print("{0} has been used: {1}x".format(func.__name__, wrapper.count))
        return res

    wrapper.count = 0
    return wrapper


@counter
def system_out(string):
    print(string)
    

system_out("A")
system_out("B")
# A
# system_out has been used: 1x
# B
# system_out has been used: 2x

装饰器常用场景及代码实现

日志打印,权限控制,处理函数超时(待更新)

参考

https://stackoverflow.com/que...

https://zhuanlan.zhihu.com/p/...

https://zhuanlan.zhihu.com/p/...

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章