• python_闭包、装饰器


     

    装饰器

    函数名的应用

      直接打印函数名得到的是函数的内存地址。

    def func1():
        print(666)
    print(func1)

      函数名可以赋值运算。

    def func1():
        print(666)
        
    f1 = func1
    f1()

      函数名可以作为函数的参数。

    def func1():
        print(666)
    
    def func2(x): x() print(555) func2(func1)

      函数名可以作为容器类数据类型的元素。

    def func1():    
        print(666)
        
        
    def func2():
        print(222)
    
    
    def func3():
        print(111)
    
    
    def func4():
        print(777)
        
        
    l1 = [func1, func2, func3, func4]
    for i in l1: i()

    def func1():
        print(666)
    
    
    def func2():
        print(222)
    
    
    def func3():
        print(111)
    
    
    def func4():
        print(777)
    
    
    dic1 = {
        1: func1,
        2: func2,
        3: func3,
        4: func4,
    }
    dic1[1]()

      函数名可以当做函数的返回值。  

    def func1():
        print(666)
    
    
    def func2(x):
        print(222)
        return x
    
    ret = func2(func1)
    ret()

    闭包

      内层函数对外层函数的非全局引用就叫闭包。

      判断是不是闭包,函数名:__closure__ 

      返回None则不是闭包;返回cell就是闭包。 

    def func1():
        name = '老男孩'
    
        def inner():
            print(name)
    inner()
    print(inner.__closure__) func1()

      

      global声明了一个全局变量,此时name为全局变量,所以就不时闭包。

    def func1():
        global name     # 声明全局变量name
        name = '老男孩'
    
        def inner():
            print(name)
    
        inner()
    print(inner.__closure__) func1()

    def func1(x):
    def inner(): print(x)
    inner()
    print(inner.__closure__) name = '老男孩'
    func1(name)

    def func():
    def func1(): name = "老男孩" def func2(): nonlocal name    # 对父级变量改变 name = "alex" def func3(): global name    # 声明一个全局变量 name = "太白" name = "日天" func1() print(name)
    func2() print(name)
    func3() print(name) func() print(name)

       当代码从上到下加载到func()时,代码开始执行。跳到func函数体里边,加载函数func1、func2、func3,加载到func1()时执行函数func1,执行完后打印name,print(name)在函数func的作用域中,所以此时name的值为'日天';加载到fun2()时,执行函数func2,此时修改了函数func2的父作用域中的name的值为'alex',也就是函数func中name的值,打印name时,找的是func作用域中的name,此时name的值为'alex';加载到func3()时,开始执行func3,此时修改了全局变量name的值为'太白',完了打印name时,此时print(name)所在的是func的作用域,由于func2修改了func作用域中name的值为'alex',所以此时name的值依旧为'alex';现在来到了最后一行代码处,此时name找的是全局作用域中name的值,由于函数func3修改了全局作用域中name的值为'太白',所以最后输出为太白。

       执行顺序如下:

    闭包的作用

      当执行一个函数时,如果解释器判断此函数内部闭包存在,这样Python就存在一个机制,闭包所在的临时名称空间不会随着函数的执行完毕而消失。

    from urllib.request import urlopen
    
    
    def index():
        url = "https://user.qzone.qq.com/569894146/infocenter"
    
        def get():
            return urlopen(url).read()
        return get
    
    
    kongjian = index()
    content = kongjian()
    
    print(content)
    

    装饰器

    函数方式

      使用函数的方式,来为另外一个函数添加功能。

    import time
    
    
    def login():
        time.sleep(0.3)
        print('洗洗更健康...')
    
    
    def timmer():
        start_time = time.time()
        login()
        end_time = time.time()
        print('此函数的执行时间%s' % (end_time - start_time))
    
    
    timmer()

    改变了原来执行函数的方式

      将函数作为参数传递到装饰器函数中,实现简单的通用装饰函数。

    def login():
        time.sleep(0.3)
        print('洗洗更健康...')
    
    
    def register():
        time.sleep(0.4)
        print('洗洗更健康22222...')
    
    
    def timmer(f):
        start_time = time.time()
        f()
        end_time = time.time()
        print('此函数的执行时间%s' % (end_time - start_time))
    
    
    timmer(login)
    timmer(register)

    初级装饰器

    def login():
        time.sleep(0.3)
        print('洗洗更健康...')
    
    
    def timmer(f):
        def inner():
            start_time = time.time()
            f()
            end_time = time.time()
            print('此函数的执行时间%s' % (end_time - start_time))
    
        return inner
    
    
    login = timmer(login)
    login()

      函数执行顺序:

        加载函数login、函数timmer,然后加载login = timmer(login),这一步执行了函数timmer,并且将login函数作为参数传给了函数timmer,然后加载函数dinner,将inner return出去,此时的login接收的是函数timmer的返回值,也就是login此时已经是函数inner了,最后login加括号执行的是函数inner。

      这里边的几个坑就是赋值,不要被login = timmer(login)赋值所干扰了。

    简单版装饰器 语法糖

      下边这个是简单版的装饰器,我们一起来看下它的执行顺序。

    def timmer(f):  # f = login函数名
        def inner():
            start_time = time.time()
            f()  # login()
            end_time = time.time()
            print('此函数的执行时间%s' % (end_time - start_time))
    
        return inner
    
    
    @timmer  # login = timmer(login)  # inner 此login是新变量
    def login():
        time.sleep(0.3)
        print('洗洗更健康...')
    
    
    login()
    
    
    @timmer  # register = timmer(register)
    def register():
        time.sleep(0.2)
        print('洗洗更健康22...')
    
    
    login()  # inner()

      执行顺序:

      下边的函数register的执行顺序是在函数login执行完以后开始执行的,调用顺序与函数login是一致的。但是它的加载是在login函数加载完成以后加载的。

    被装饰的函数带参数的装饰器

      下边我们来看下带参数的装饰器是如何进行参数的传递和执行的:

    def timmer(f):  # f = login函数名
        def inner(*args, **kwargs):  # args (2, 3)
            start_time = time.time()
            f(*args, **kwargs)  # login() *(2, 3) 2,3
            end_time = time.time()
            print('此函数的执行时间%s' % (end_time - start_time))
    
        return inner
    
    
    @timmer  # login = timmer(login)  # inner 此login是新变量
    def login(a, b):
        print(a, b)
        time.sleep(0.3)
        print('洗洗更健康...')
    
    
    login(2, 3)  # inner(2,3)
    
    
    @timmer  # register = timmer(register)
    def register(a):
        time.sleep(0.2)
        print('洗洗更健康22...')
    
    
    register(1)  # inner(1)

      执行顺序:

      上图中,蓝色的为函数的传递过程;绿色的为参数的传递过程。下边的register函数的执行与参数的传递过程一致。

    函数带返回值的装饰器(万能装饰器)

      下边是一个功能完善的装饰器,我们一起来看下他的参数传递以及执行过程:

    def timmer(f):  # f = login函数名
        def inner(*args, **kwargs):  # args (2, 3)
            start_time = time.time()
            ret = f(*args, **kwargs)  # login() *(2, 3) 2,3
            end_time = time.time()
            print('此函数的执行时间%s' % (end_time - start_time))
            return ret
    
        return inner
    
    
    @timmer  # login = timmer(login)  # inner 此login是新变量
    def login(a, b):
        print(a, b)
        time.sleep(0.3)
        print('洗洗更健康...')
        return 666
    
    
    print(login(2, 3))  # inner(2,3)

      装饰器的执行顺序、参数、返回值的传递过程:

      其中绿色的为参数的传递过程,紫色的为返回值传递的过程。

    装饰器模板

      下边的是满满的干货,你可以不知道执行顺序,但是你要知道怎么用,没错儿,背过他就行了。

    def wrapper(f):
        def inner(*args, **kwargs):
            '''执行被装饰函数之前的操作'''
            ret = f(*args, **kwargs)
            """执行被装饰函数之后的操作"""
            return ret
    
        return inner

    装饰器的作用

        在不改变原函数的基础场,为原函数增加一些功能,log、登录注册等。

  • 相关阅读:
    C#重载操作符的那点事
    Winform最小化托盘
    C#多线程传参
    GridView事件大全
    测试2
    测试
    FindFileByContent
    JavaScriptCallCSharp js调用C#属性与方法
    GroupBy
    查询指定属性的文件
  • 原文地址:https://www.cnblogs.com/ZN-225/p/9587924.html
Copyright © 2020-2023  润新知