Python之装饰器

装饰器:
定义:本质是函数,(装饰其他函数)就是为其他函数添加附加功能

需要遵从两条原则:

1.不能修改被装饰的所数的源代码
2.不能修改被装饰的函数的调用方式

例如有一段这样的代码

(1)

def test1():
    time.sleep(3)
    print('this is test1')

现在有一个要求,不改动原有的代码统计这个函数的运行时间。你可能会这样写。

(2)

import time
def test1():
    time.sleep(3)
    print('this is test1')
def func(test1):
    start_time=time.time()
    test1()
    stop_time=time.time()
    print("test1 run time is %s",stop_time-start_time)
func(test1)

这样确实是在不改动原有的代码统计了test1的运行时间,但是这并不是装饰器,它没有遵从第二条原则不能修改被装饰的函数的调用方式,它调用的是func函数而并非test1函数。这样调用的不好之处就是,如果我们的程序中有多个地方用到了test1这个函数,我们使用这种方式扩展test1的功能时,我们就要在多个地方修改原有的代码,带来了极大的不便。

装饰器需要了解的知识:

 

1.函数即变量

2.高阶函数
a:把一个函数名当做实参传给另外一个函数(在不修改被装饰函数源代码的情况下为其添加功能)  例如:(2)中的例子
b:返回值中包含函数名(不修改函数的调用方式)

import time
def bar():
    print('in the bar')
def test2(func):
    print("扩展功能")
    return func
bar=test2(bar)
bar()  #run bar

该案例利用test2函数为bar扩展了新功能,test2(bar)函数返回的是bar的地址,这样初步实现了不修改函数名就扩展了bar的功能。

3.嵌套函数

x=0
def grandpa():
    x=1
    def dad():
        x=2
        def son():
            x=3
            print(x)
        son()
    dad()
grandpa()

嵌套函数要让它起作用,必须在当层调用否则嵌套函数或者它的子函数无效。例如案例中的dad()去除,那么dad函数和它下面的son函数都无效。

高阶函数+嵌套函数=装饰器

装饰器就很好的解决了之前提出的那个问题,在不改动原有的代码扩展功能。

import time
def decorator(func):
    def warpper():
        start_time=time.time()
        func()
        stop_time=time.time()
        print('the func run time is %s' %(stop_time-start_time))
    return warpper
@decorator #test1=decorator(test1)
def test1():
    time.sleep(3)
    print('this is test1')
test1()

@decorator相当于test1=decorator(test1)

运行的流程大概是这样了

由于python是解释性语言,一行一行走下来并解释,首先走到decorator函数这里,由于没有这里还没有调用,前面说过函数即变量,就相当于把这个变量加载到内存当中,并不会走到里面。接着走到@decorator,由于@decorator修饰test1的,调用了decorator函数,并把test1的地址传入,这时func=test1,把warpper函数加载到内存当中,然后返回warpper函数的地址并赋值给test1,此时test1=warpper(偷梁换柱),最后执行test1(),也就是执行warper这个函数,计算开始时间,执行func(),这个func是之前传来的test1,没有被修改成warpper地址之前的,然后休眠3秒,得到时间差。

可以用debug来查看运行的过程,我也是看了好久才理明白。

如果函数需要传出参数,(一个或者多个)可以这样写。

import time
def decorator(func):
    def warpper(*args,**kwargs):
        start_time=time.time()
        func(*args,**kwargs)
        stop_time=time.time()
        print('the func run time is %s' %(stop_time-start_time))
    return warpper

@decorator #相当于test1=decorator(test1)
def test1(name1,name2):
    time.sleep(3)
    print('this is test1 %s %s',name1,name2)
test1("arg1","arg2")

(*args,**kwargs)可以传任意个参数。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

原飞木

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值