python装饰器理解


python装饰器也是从很少之前就接触了,由于都是自己学习,我的应用场景中又很少用到,就一直搁置了,最近又学习了一下。写一下理解,欢迎道友批评指正。

为什么要有装饰器

在实际的应用场景中,需要记录函数的执行过程和函数的运行状态,比如说日志系统、函数的运行时间、函数的异常状态、返回值等。而在项目中,很多函数都需要进行这样的操作,那么怎么来实现呢?

第一种方式:我们可以在每一个函数中,都增加相应的代码,对函数执行状态进行记录。但是这样有一些问题。每个函数中都需要增加与业务功能无关的代码,并且每一个函数都进行这个的功能,不同的人编写各自的业务函数的时候,对于这些通用的功能,代码可能会产生不一致性。容易出错。

第二种方式:就是通过装饰器来实现。把通用的这些功能通过装饰器来实现,业务功能用函数来实现。把业务函数与装饰器结合,可以实现对函数状态的记录。

装饰器长什么样子

我通过以下代码分享一下我对装饰器的理解。
** 定义业务函数**
业务函数中,不需要考虑添加记录函数状态的代码,只专注于业务功能的开发。

def myFunction(timer_set=2):
    time.sleep(timer_set)
    print("程序执行结束")

定义装饰器函数
在开始介绍装饰器函数前,先介绍一下一下闭包的概念。如果一个函数myDecorator中,定义了另一个函数wrapper,myDecorator函数的返回值是内部定义的函数wrapper,这样就构成了一个闭包。
在闭包中,内部函数可以使用外部函数的变量。

我们这样实现装饰器,如下面代码所示:
我们把记录函数状态的代码写在内部函数wrapper里面,

def myDecorator(func_name):
    def wrapper(*args, **kwargs):
        st = time.time()
        print("{} is running".format(func_name.__name__))
        f = func_name(*args, **kwargs)
        et = time.time()
        print("程序耗时:", et-st)
        return f
    return wrapper

函数调用
函数调用时,经过装饰器修饰,返回内部函数,而内部函数就是公用功能和业务函数的结合体,就实现了我们的目标。

decorator = myDecorator(myFunction)
decorator()
myFunction is running
程序执行结束
程序耗时: 2.003638505935669

python装饰器的实现方式

@符号函数实现

上述的代码,解释了python装饰器的基本实现,但是我们发现,调用时,还是有些繁琐,需要调用装饰器函数修饰业务函数,多少有些麻烦,有没有更简洁的实现的呢?
答案是有的,python中,可以使用@符号,实现装饰器函数对业务函数的修饰。这个过程在业务函数定义时完成,如代码所示,这样,调用时,就不用考虑装饰器了。当然,实现也很简单。
定义装饰器
这部分代码没有变化

import time
def myDecorator(func_name):
    def wrapper(*args, **kwargs):
        st = time.time()
        print("{} is running".format(func_name.__name__))
        f = func_name(*args, **kwargs)
        et = time.time()
        print("程序耗时:", et-st)
        return f
    return wrapper

定义业务函数
如以下代码所示,这样的话,可以完成了业务函数的定义,输出结果和前面一样

@MyDecorator
def myFunction(timer_set=2):
    time.sleep(timer_set)
    print("程序执行结束")

@符号函数实现(带参数)

can_run = False
def myDecorator(param_can_run):
    def middle(func_name):
        def wrapper(*args, **kwargs):
            if param_can_run==True:
                st = time.time()
                print("{} is running".format(func_name.__name__))
                f = func_name(*args, **kwargs)
                et = time.time()
                print("程序耗时:", et-st)
            else:
                print("program is not running")
        return wrapper
    return middle

函数定义
函数定义中,只需要在@代码后面传入参数即可

can_run = True
@myDecorator(can_run)
def myFunction(timer_set=2):
    time.sleep(timer_set)
    print("程序执行结束")
myFunction(timer_set=2)

这种调用方式,等价于不带@的调用如下进行

can_run = True
f_middle = myDecorator(can_run)
f_wrapper = f_middle(myFunction)
f_wrapper(timer_set=2)

类实现

以上功能可以考虑使用类来实现
定义装饰器
这部分代码没有变化

import time
class MyDecorator(object):
    def __init__(self, func_name):
        self._func_name = func_name
        
    def __call__(self, *args, **kwargs):
        st = time.time()
        print("{} is running".format(self._func_name.__name__))
        self._func_name(*args, **kwargs)
        et = time.time()
        print("程序耗时:", et-st)

定义业务函数
如以下代码所示,这代码不需要变化,@符号后面不再是函数名,而是类名

@MyDecorator
def myFunction(timer_set=2):
    time.sleep(timer_set)
    print("程序执行结束")

python的装饰器工具

以上代码我们把函数说明加上


def myDecorator(func_name):
    """this is decorator """
    def wrapper(*args, **kwargs):
        """this is wrapper"""
        st = time.time()
        print("{} is running".format(func_name.__name__))
        f = func_name(*args, **kwargs)
        et = time.time()
        print("程序耗时:", et-st)
        return f
    return wrapper
@myDecorator
def myFunction(timer_set=2):
    """this is business function"""
    time.sleep(timer_set)
    print("程序执行结束")

查看函数文档

myFunction.__doc__

输出如下所示

'this is wrapper'

显然,文档说明不对,python提供了工具,可以对这个问题进行修改,代码修改如下:


from functools import wraps
def myDecorator(func_name):
    """this is decorator """
    @wraps(func_name) # 添加此处代码
    def wrapper(*args, **kwargs):
        """this is wrapper"""
        st = time.time()
        print("{} is running".format(func_name.__name__))
        f = func_name(*args, **kwargs)
        et = time.time()
        print("程序耗时:", et-st)
        return f
    return wrapper
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值