• Python之闭包函数、装饰器


    1、闭包函数

    #作用域关系在函数定义阶段时就已经固定死了,与调用位置无关
    # 即:在任意位置调用函数都需要跑到定义函数时寻找作用域关系
    
    # def f1():
    #     x=1
    #     def inner():
    #         print(x)   #闭包的含义:内部函数中的变量x引用外部作用域的x,而非全局作用域的x
    #     return inner
    # func=f1()          #f1()=inner
    #
    #
    # def f2():
    #     x=111111
    #     func()        #func()=inner()
    # f2()
    
    
    # 闭包函数:
    # 闭指的是:该函数是一个内部函数
    # 包指的是:指的是该函数包含对外部作用域(非全局作用域)名字的引用
    # def outter():
    #     x = 1
    #     def inner():
    #         print(x)        #内部函数inner中的x是对外部作用域的引用,而非全局作用域的引用
    #
    #     return inner
    #
    # f=outter()
    #
    # def f2():
    #     x=1111111
    #     f()
    #
    # f2()
    #
    #
    # def f3():
    #     x=4444444444444
    #     f()
    #
    # f3()
    
    
    # 为函数传值的两种方式:
    # 为函数体传值的方式一:使用参数的形式
    # def inner(x):
    #     print(x)
    #
    # inner(1)
    # inner(1)
    # inner(1)
    
    
    # 为函数体传值的方式二:包给函数
    '''
    def outter(x):
        # x=1
        def inner():
            print(x)    #通过闭包函数将值报给内部函数
        return inner
    
    f=outter(1)
    f()
    '''
    
    
    # 例子:
    # 方法一:通过传参的形式将值传给函数内的变量
    # import requests
    # def get(url):
    #     response=requests.get(url)
    #     if response.status_code == 200:
    #         print(response.text)
    #
    # get('https://www.baidu.com')
    # get('https://www.baidu.com')
    # get('https://www.baidu.com')
    #
    # get('https://www.python.org')
    # get('https://www.python.org')
    # get('https://www.python.org')
    # get('https://www.python.org')
    
    
    # 方法二:通过闭包函数将值包给其内部的函数
    import requests
    def outter(url):                             #通过传参的形式,可以爬去任意网页的源代码
        # url='https://www.baidu.com'            #功能被写死,所以改成传参的形式
        def get():
            response=requests.get(url)           #url是通过outter函数,将值包给函数get内的函数体代码用的
            if response.status_code == 200:      #成立说明,成功爬去网页的源代码
                print(response.text)
        return get                               #返回get给外部的调用者,打破层级的限制(函数对象的知识)
    
    baidu=outter('https://www.baidu.com')        #本质就是传入了参数的get的内存地址
    python=outter('https://www.python.org')
    
    
    baidu()                                      #本质就是已经给url传入了参数的get的内存地址,加括号即调用
    baidu()
    
    python()
    python()

    2、装饰器

    '''
    1、什么是装饰器
        器指的是工具,而程序中的函数就具备某一功能的工具
        装饰指的是为被装饰器对象添加额外功能
    
        就目前的知识来看:
            定义装饰器就是定义一个函数,只不过该函数的功能是用来为
            其他函数添加额外的功能
    
        其实:
            装饰器本身其实可以是任意可调用的对象
            被装饰的对象也可以是任意可调用的对象
    
    
    2、为什么要用装饰器
        软件的维护应该遵循开放封闭原则
        开放封闭原则指的是:
            软件一旦上线运行后对修改源代码是封闭的,对扩展功能的是开放的
            这就用到了装饰器
    
        装饰器的实现必须遵循两大原则:
            1、不修改被装饰对象的源代码
            2、不修改被装饰对象的调用方式
        装饰器其实就在遵循1和2原则的前提下为被装饰对象添加新功能
    
    3、如何用装饰器
    '''
    
    
    # 方式一
    # 给原函数添加上了新功能,没有改变原函数的调用方式,但是却改变了源代码
    import time
    # def index():
    #     start=time.time()
    #     print('welcom to index')
    #     time.sleep(3)
    #     stop=time.time()
    #     print('run time is %s' %(stop-start))
    # index()
    
    # 方法二
    # 没有改变源代码,也没有改变调用方式,但是给不同函数扩展相同的功能时,是在重复写代码的过程
    import time
    # def index():
    #     print('welcom to index')
    #     time.sleep(3)
    #
    # def f2():
    #     print('from f2')
    #     time.sleep(2)
    
    # 以下为两个函数添加上了引得功能,但是重复写代码
    # start=time.time()
    # index()
    # stop=time.time()
    # print('run time is %s' %(stop-start))
    # #
    # start=time.time()
    # f2()
    # stop=time.time()
    # print('run time is %s' %(stop-start))
    
    
    # 方法三
    # 将重复写代码的过程,定义为一个函数的功能,虽然没有该源代码,但是改变了函数的调用方式
    # import time
    #
    # def index():
    #     print('welcom to index')
    #     time.sleep(3)
    #
    # def timmer(func):
    #     start=time.time()
    #     func()
    #     stop=time.time()
    #     print('run time is %s' %(stop-start))
    #
    # timmer(index)
    
    # 方法四
    # 利用闭包函数,为函数添加上新的功能
    
    '''
    import time
    def index():
        print('welcom to index')
        time.sleep(3)
    
    def timmer(func): #func=最原始的index
        # func=index           #这样就把被装饰的对象写死了,所以需要以传参的形式将,被装饰的函数传进来
        def inner():
            start=time.time()
            func()
            stop=time.time()
            print('run time is %s' %(stop-start))
        return inner
    
    # f=timmer(index)
    # f()
    
    # index=timmer(被装饰函数的内存地址)
    index=timmer(index) #index=inner
    
    index() #inner()
    
    
    '''
    import time
    
    def index():
        print('welcom to index')
        time.sleep(3)
    
    def timmer(func):        #将被装饰的函数传进来,不至于将被装饰的对象写死,固定是某一个,而是可以装饰任意一个函数
        #func=最原始的index ,即被装饰函数的的内存地址
        def wrapper():       #该函数即是为被装饰函数添加上的新功能
            start=time.time()
            func()           #最原始的index加括号即使调用最原始的函数
            stop=time.time()
            print('run time is %s' %(stop - start))
        return wrapper       #函数对象知识:返回给外部函数调用,打破层级限制
    
    index=timmer(index)      #左边的index=wrapper函数的内存地址,右边的index即是我们要装饰的函数
    index()                  #本质调用的是wrapper函数

    三、装饰器修正

    import time
    def index():                                    #被装饰的函数无参,有返回值
        print('welcome to index')
        time.sleep(3)
        return 123
    
    def home(name):                                #被装饰的函数有参,没有返回值
        print('welcome %s to home page' %name)
        time.sleep(2)
    
    
    def timmer(func):
        #func=最原始的index
        def wrapper(*args,**kwargs):                #wrapper会将接收的参数,原封不动的传给被装饰的函数
            start=time.time()
            res=func(*args,**kwargs)                #因为被装饰的对象可能有的有参,有的是无惨,所以调用时用*args,**kwargs,无论有无参数都不会报错
            stop=time.time()
            print('run time is %s' %(stop - start))
            return res                              #接收被装饰函数的返回值,被装饰的函数没有返回值则为None,有则返回被装饰的返回值
        return wrapper                              #该返回值则是返回给外部函数用的,可以打破层级的限制,这样内部函数即给被装饰函数添加的新功能就可以被调用到
    
    
    index=timmer(index)                             #将被装饰的函数传入,调用装饰器,本质就是调内部被加上新功能的函数
    home=timmer(home)                               #将被装饰的函数传入,调用装饰器,本质就是调内部被加上新功能的函数
    
    res=index()                                     #拿到调用函数的返回值,打印即可看到返回值
    home('egon')                                    #被装饰的函数为有参,为被装饰函数进行传参
    print(res)
    
    #装饰器语法糖
    # 在被装饰对象正上方,并且是单独一行写上@装饰器名
    # import time
    # def timmer(func):
    #     #func=最原始的index
    #     def wrapper(*args,**kwargs):
    #         start=time.time()
    #         res=func(*args,**kwargs)
    #         stop=time.time()
    #         print('run time is %s' %(stop - start))
    #         return res
    #     return wrapper
    #
    # @timmer # index=timmer(index)   #timmer即一个名字,所以装饰器的代码块要写在timmer的上方,@timmer本质就是调用了timmer(传入被装饰的函数名)
    # def index():
    #     print('welcome to index')
    #     time.sleep(3)
    #     return 123
    #
    # @timmer # home=timmer(home)
    # def home(name):
    #     print('welcome %s to home page' %name)
    #     time.sleep(2)
    #
    # res=index()
    # home('egon')
    
    
    # 装饰器的万能模板:
    def deco(func):                   #func即是要接收的被砖石的函数名
        def wrapper(*args,**kwargs):  #可以根据被装饰的函数需不需要传参,给被装饰的对象传入参数
            res=func(*args,**kwargs)  #本质就是调用被装饰的函数, 接收传进来的参数
            return res                #接收被装饰函数的返回值,没有则返回None
        return wrapper                #外部函数将内部函数的内存地址返回,打破层级限制
  • 相关阅读:
    配置好IIS中的SMTP服务器
    金秋十月
    "小生"的Google搜索结果
    "苏州大本营"腐败大会第三次顺利召开
    我修改了半年的密码还没有成功修改,dudu你能修改吗?
    好资源大家分享
    利用Google来调用其他网站查询信息
    推荐一本书<<专家门诊——ASP.NET开发答疑200问>>
    谁能给我一个FeedDemon v1.1的序列号或者注册文件
    毕业2月有余,苏州同学腐败第二次大聚会
  • 原文地址:https://www.cnblogs.com/sui776265233/p/9168920.html
Copyright © 2020-2023  润新知