ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

20220812-day1601重要的装饰器

2022-08-12 21:02:42  阅读:161  来源: 互联网

标签:函数 show day1601 20220812 time print foo 装饰 def


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

#_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)

 

标签:函数,show,day1601,20220812,time,print,foo,装饰,def
来源: https://www.cnblogs.com/ly-zy/p/16580925.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有