python装饰器快速了解

一、首先,理解装饰器的初衷:不改变原函数的原则

举个栗子,这里有3个函数,实现各自的逻辑功能

def a():
    #此方法需要实现某业务A
    print('此处代替实现业务A的逻辑代码')

def b():
    #此方法需要实现某业务B
    print('此处代替实现业务B的逻辑代码')

def c():
    #此方法需要实现某业务C
    print('此处代替实现业务C的逻辑代码')

下一步,我们想在这里任意一个函数执行时,执行与业务逻辑不相干的某事,比如打印函数名

粗暴一点,为所有函数添加print(func.__name__)

def a():
    #此方法需要实现某业务A
    print(a.__name__)
    print('此处代替实现业务A的逻辑代码')

def b():
    #此方法需要实现某业务B
    print(b.__name__)
    print('此处代替实现业务B的逻辑代码')

def c():
    #此方法需要实现某业务C
    print(c.__name__)
    print('此处代替实现业务C的逻辑代码')

那么问题来了,即便此处将print(func.__name__)方法封装抽离,一样改变了函数abc本身的逻辑,而且当我们想要使用比较复杂的函数(比如计时器函数、超时器)时,abc的代码就会变得难以维护

尝试使用装饰器来实现

def outter(func):
    def inner():
        print(func.__name__)
        func()
    return inner

@outter
def a():
    #此方法需要实现某业务A
    print('此处代替实现业务A的逻辑代码')

@outter
def b():
    #此方法需要实现某业务B
    print('此处代替实现业务B的逻辑代码')

@outter
def c():
    #此方法需要实现某业务C
    print('此处代替实现业务C的逻辑代码')

当我们调用a()时,实际执行的是:outter(a)()

,这里的a则是作为参数传入了outter方法      #这其实就是装饰器的核心:将被装饰函数作为参数传入装饰器函数执行

我们继续看outter(a)()的实际执行步骤,看注释

def outter(func):
    def inner():
        print(func.__name__)
        func()

    #函数outter会直接执行的,就只有这一句renturn 而已
    return inner

'''
1、
可以看到outter(a)的返回值就是函数inner
所以outter(a)()就是inner()

2、
内函数inner所调用的func就是从外函数outter传进来的函数a
那么inner()所做的,就是先打印a的函数名,然后再执行a()


'''

这样,就实现了本文开头所说的,装饰器的不改变原函数原则,借此实现装饰器逻辑与原函数代码的完全分离

这么做最大的好处就是允许我们在业务逻辑执行过程中,添加与业务无关且复杂的操作

二、了解了装饰器基本使用之后,我们再来看看被装饰函数的参数传递

因为被装饰的函数往往具有不同的参数集,所以装饰器函数在处理被装饰函数的参数时,使用(*args,**kwargs)来代替被装饰函数的形参

def outter(func):
    def inner(*arg,**keargs):
        print(*arg)
        print(**kwargs)    

        print(func.__name__)
        func(*args,**kwargs)
    return inner

@outter
def a(name,age):
    #此方法需要实现某业务A
    print('此处代替实现业务A的逻辑代码')

@outter
def b(hight):
    #此方法需要实现某业务B
    print('此处代替实现业务B的逻辑代码')

@outter
def c(weight):
    #此方法需要实现某业务C
    print('此处代替实现业务C的逻辑代码')

if __name__ == "__main__":
    a(1,age=2)
    b(3)
    c(weight=4)


可以看到abc函数的实际调用格式完全不可控,使用*args获取函数的非关键字参数,比如1,3,生成list格式传递;使用**kwargs获取关键字参数,例如age=2,weight=4,生成dict格式传递

三、最后来看装饰器函数的参数传递

比较常见的是超时器设置,常用于设置某一行为的超时限制

举个简单的栗子

import time
def timelimited(timeout):
    def ouuter(function):
        def inner(*args, **kwargs):
            print('这里只是证明timeout参数可以正常传进来',timeout)


            function(*args, **kwargs)
            #注释A

        return inner
    return ouuter


@timelimited(2)  # 设置运行超时时间2S
def a(secs):
    print('这里代替业务逻辑')


if __name__ == "__main__":
    fn_1(5)

只要在注释A的位置使用多线程实现计时和关闭的功能,一个计时器就开发完成了(了解完整代码参见下一章python计时器)

这里可以看到只要借助装饰器,即便是超时器这样的复杂函数也可以实现,并且完全实现了不改变原函数的初衷

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值