zoukankan      html  css  js  c++  java
  • 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、登录注册等。

  • 相关阅读:
    10 个雷人的注释,就怕你不敢用!
    Java 14 之模式匹配,非常赞的一个新特性!
    poj 3661 Running(区间dp)
    LightOJ
    hdu 5540 Secrete Master Plan(水)
    hdu 5584 LCM Walk(数学推导公式,规律)
    hdu 5583 Kingdom of Black and White(模拟,技巧)
    hdu 5578 Friendship of Frog(multiset的应用)
    hdu 5586 Sum(dp+技巧)
    hdu 5585 Numbers
  • 原文地址:https://www.cnblogs.com/ZN-225/p/9587924.html
Copyright © 2011-2022 走看看