20220812-day1601重要的装饰器

2022/8/12 23:57:59

本文主要是介绍20220812-day1601重要的装饰器,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

装饰器实质就是一种特殊的函数。要了解装饰器,首先要了解闭包。

#_author: Administrator
#_date: 2020/5/25

#闭包  就是满足下面两个条件(条件一、二)的一个函数
def outer():
    x = 10
    def inner(): #条件一   inner()就是内部函数
        print(x) #条件二    x外部环境的一个变量
    return inner #将函数名作为了返回值。内部函数inner就是一个闭包
#问题:我们怎么能调用上面的inner函数?
# outer()() #调用方式1
# f = outer() #调用方式2
# f()

#那除了上面两种方式,还有别的调用方式吗?接下来往下看
# inner() #直接调用inner函数是会报错的NameError: name 'inner' is not defined。报错类似于直接调用函数里的变量一样。局部变量,全局无法调用:如下
# print(x) #NameError: name 'x' is not defined

#接下来再想想,下面这种调用方式。可以发现执行f = outer()的时候,outer函数已经执行完了,为什么执行f()函数不会出错呢?其实这就是闭包。
f = outer() #调用方式2
f()
#有点难理解吧,直接看闭包定义:如果在一个内部函数里[inner()],对在外部作用域(但不是在全局作用域)的变量[x变量]进行引用,那么内部函数[inner()]就被认为是闭包。
#由上可知,闭包就是符合上面条件的函数。那有什么用呢?闭包函数可以脱离局部环境,可以在外面进行调用,这就是为什么上面的f()是可以执行的。

#上面闭包结束了,接下来看看装饰器
#首先看一个例子:一个公司有一个人写了很多函数,公司的人都可以调用。但有一天boss要求对原函数做出点调整,难道自己直接改原函数吗?岂不是如果改错了,所有的全都错了!!因此需要遵循“开放封闭”原则,即不能修改源代码,但能扩展
import time
def foo():
    print("foo.....")
    time.sleep(1)
def bar():
    print("bar....")
    time.sleep(3)
#假如有很多这样的原函数。但现在要求给每个函数加上每个函数的执行时间,该怎么做呢?可以如下:写个专门记录时间的函数
def show_time(*args):
    for i in args:
        start=time.time()
        i()
        end=time.time()
        print("Spend time: %s" %(end-start))
show_time(foo, bar)

#但是问题出现了,虽然实现了功能,但致命问题出现了:修改了调用方式(以前调用foo(),现在要调用show_time()),这是很致命的!!!
#怎么整呢?
def show_time2(f):
    def in_fun():
        start=time.time()
        f()
        end=time.time()
        print("Spend time2: %s" %(end-start))
    return in_fun #这里in_fun就是个闭包函数
foo=show_time2(foo) #这样就没有修改原来的调用方式了
foo() #执行的in_fun函数
bar=show_time2(bar)
bar()
#所以装饰器就出来了:就是给原函数添装新的功能。这里的show_time2()就是一个装饰器

#上面的又出来了:给那个函数加功能,就要给那个函数赋值一次,所以出现了一种改进写法@,如下:
@show_time2 #实质就是等于foo_re=show_time2(foo_re)
def foo_re():
    print("foo_re.....")
    time.sleep(2)
foo_re()
#以后想在哪个原函数加上计时功能,只需要在原函数前添加@show_time2就行了
#是不是成就感满满
#当然还有缺点,如果有一万个函数都要加这个功能呢?有没有什么批量添加方法???这里还没法解决,还得继续后面学习。

#装饰器已经学完了,但可以进一步学习一下。先看个需求:假如其中一个原函数有参数呢,该怎么做?
#只能真对性再定义个函数。如下:
def show_time3(f):
    def in_fun(x,y):
        start=time.time()
        f(x,y)
        end=time.time()
        print("Spend time2: %s" %(end-start))
    return in_fun
@show_time3
def add(a,b):
    print(a+b)
    time.sleep(1)
add(1,4)
#那问题来了,万一各个原函数之间存在不同数目的参数呢??没有讲

#功能函数加参数,就会带动装饰器函数必须加参数。但可不可以单独给装饰器函数加参数呢??当然可以
#需求:对于有些原函数,不仅要打印时间,还要显示日志。看下面:
def logger(flag): #再加一层的目的就是要一个参数,用于下面的if判断
    def show_time3(f):
        def in_fun(x,y):
            start=time.time()
            f(x,y)
            end=time.time()
            print("Time_log spend time2: %s" %(end-start))
            if flag == "true":
                print("日志记录")
        return in_fun #这里in_fun就是个闭包函数
    return show_time3
@logger("true")
def fil(a,b):
    print(a+b)
    time.sleep(1)
fil(1,4)

@logger("t")
def fil2(a,b):
    print(a+b)
    time.sleep(1)
fil2(2,3)

 



这篇关于20220812-day1601重要的装饰器的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程