Skip to main content

Python小知识 - 装饰器

Python小知识 - 装饰器

Python小知识 - 装饰器

装饰器本质上是一个Python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象。它经常用于有切面需求的场景,比如:插入日志、性能测试、事务处理、缓存、权限校验等场景。装饰器是解决这类问题的绝佳设计,有了装饰器,我们就可以抽离出大量与函数功能本身无关的雷同代码并继续重用。概括的讲,装饰器的作用就是为已经存在的对象添加额外的功能。

比如我们有个函数,如下

def do_get():
    """
    docstring
    """
    print('do get')

有个需求,需要给这个函数增加一个日志,记录这个函数的执行日志,于是在代码中添加日志代码如下

def do_get():
    print('do get')
    logging.info('go get logging')

但是如果我们要给类似的函数都加上函数的执行日志,会造成大面积的修改,如果一两个函数还是可以的

但是如果有很多的函数需要添加,就需要大量的工作,这个是不可取的

所以需要一个专门来处理日志的函数

import logging

def do_logging(func):
    logging.warning(f"{func.__name__} is running")
    func()

def do_get():
    print("do get")

do_logging(do_get)

但是这样的话,需要每次将一个函数作为参数传递给do_logging函数,也不是非常理想

于是我想到了装饰器

import logging

def do_logging(func):
    def wrapper(*args, **kwargs):
        logging.warning(f"{func.__name__} is running")
        return func(*args, **kwargs)

    return wrapper

def do_get():
    print('do get')

do_get = do_logging(do_get)

do_get()

这里do_logging就是一个装饰器

'@符号'是装饰器的语法糖,在定义函数的时候使用,避免再一次赋值操作,使用方式如下

import logging

def do_logging(func):
    def wrapper(*args, **kwargs):
        logging.warning(f"{func.__name__} is running")
        return func(*args, **kwargs)

    return wrapper

@do_logging
def do_get():
    print('do get')

do_get()

使用装饰器极大地复用了代码,但是他有一个缺点就是原函数的元信息不见了

import logging
from functools import wraps


def do_logging(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        logging.warning(f"{func.__name__} is running")
        func(*args, **kwargs)

    return wrapper


@do_logging
def do_get():
    print('do get')


do_get()

 

版权声明

版权声明

张大鹏 创作并维护的 Walkerfree 博客采用 创作共用保留署名-非商业-禁止演绎4.0国际许可证。本文首发于 Walkerfree 博客(http://www.walkerfree.com/),版权所有,侵权必究。本文永久链接:http://www.walkerfree.com/article/241