zoukankan      html  css  js  c++  java
  • Day59 Python基础--闭包&装饰器

    一,函数知识点回顾

    def func():
        pass
    
    print(func)  #函数名对应内存地址
    
    a = func  #可以赋值给变量
    a()
     
    def func2(arg):  #可以做参数
        arg()
    func2(func)
    
    def func3():  #可以做返回值
        def fun4():
            pass
        return func4
    
    lis = [func,func2,func3,func4]  #可以做容器对象的元素
    for i in lis:
        i()

    二,闭包

      定义:如果一个内层函数包含了对外层函数变量的引用,那这个内层函数就是闭包

    闭包是一个特别的情况。外部函数发现,自己的临时变量会在将来的内部函数中用到,自己在结束的时候,返回内函数的同时,会把外函数的临时变量送给内函数绑定在一起。所以外函数已经结束了,调用内函数的时候仍然能够使用外函数的临时变量
    闭包底层原理简要
    def wrapper(name):
        def inner():
            print(name) #相当内层函数的空间里保留了name变量的引用并且指向当初传入的实参
        return inner
    ret = wrapper('123')  #当函数执行时,Python解释器会开辟一块内存(局部名称空间)来储存这个函数里面的内容,这个时候,Python解释器才关注函数里面变量名和值之间对应的关系,包括内层函数内的内容
    
    del wrapper
    ret()     # 指向inner的内存地址
    wrapper('123')  #报错:NameError: name 'wrapper' is not defined
    闭包如何保存局部变量的数据
    #灵魂三问1
    def func1():
        num = 100
        def func2(arg):
            print(arg)
        func2(num)  #通过传参的方式,向内层函数传递数据
    
    func1()  
    
    #灵魂三问2
    def func1():
        num = 100
        def func2()
            print(num)  #内层函数的作用域里没有num,会自动往外层函数的作用域去找
        func2()
    
    func1()
    
    #灵魂三问3
    def func1(num):
        def func2():
            print(num)  #内层函数的作用域路没有num,会自动往外层函数的作用域去找
        func2()
    
    func1()
    看起来好像很牛b的闭包灵魂三问
    #内层函数+其外层函数变量的引用
    def func1(name):
        def func2():
            print(name)
        return func2
    
    ret = func1('alex')
    ret()
    
    #非闭包
    def func1():
        def func2():
            def func3():
                def func4():
                    pass
                return func4
            return func3
        return func2
    
    ret1 = func1()  #func2
    ret2 = ret1() #func3
    ret3 = ret2() #func4
    ret3()
    闭包的变形

    三,装饰器初识 

    #装饰器的定义:
    既不想直接修改原来的函数,也不想修改函数的调用方式,还要加新功能的时候,可以使用装饰器
    def wrapper(func): def inner(*args,**kwargs): print('新功能') func(*args,**kwargs) return inner
    #global_func = wrapper(global_func) 内层的inner函数,引用了func,func -指向-> global_func
    @wrapper  #相当于把被装饰的函数当成参数传给a,然后把返回值再赋值给被装饰的函数名
    def global_func(): pass

    global_func() #相当于调用了内层函数inner

    四,装饰器进阶

      1.装饰带参数的函数

    # 装饰带参数的函数
    
    
    def wrapper(func):
        def inner(*args, **kwargs):  # 实际执行函数的参数
            print('开始')
            r = func(*args, **kwargs)
            print(r)
            print('结束')
            return r
        return inner
    
    
    @wrapper
    def my_sum(x, y):
        print('我是my_sum函数')
        return x + y
    
    
    ret = my_sum(10, 20)  # inner(10, 20)
    print(ret)

      2.装饰带返回值的函数

    # 装饰带返回值的函数
    def wrapper(func):
        def inner():
            print('开始')
            r = func()  # 拿到原来函数的返回值
            print('结束')
            return r
        return inner
    
    
    @wrapper
    def f1():
        print('我是f1')
        return 100
    
    
    ret = f1() #实际上是执行了inner内层函数,如果inner内层没用renturn返回值,则f1也没用返回值

      3.带参数的装饰器  *****

    def mougehanshu(arg):
        def wrapper(func):
            def inner(*args, **kwargs):
                print('欢迎VIP用户进入{}专栏!'.format(arg))
                func(*args, **kwargs)
            return inner
        return wrapper
    
    # wrapper = mougehanshu()
    #@mougehans(参数) 相当于 @wrapper
    
    
    @mougehanshu('电影')  # 相当于mougehanshu()执行后返回wrapper
    def movie():
        print('这是电影专栏!')
    
    
    @mougehanshu('体育')  # @wrapper
    def sport():
        print('这是体育专栏!')

      4.多个装饰器装饰同一个函数  *****

    def foo1(func):
        print("d1")
    
        def inner1():
            print("inner1")
            return "<i>{}</i>".format(func())
    
        return inner1
    
    
    def foo2(func):
        print("d2")
    
        def inner2():
            print("inner2")
            return "<b>{}</b>".format(func())
    
        return inner2
    
    
    @foo1   #f1 = foo1(foo2(f1))=foo1(inner2,打印d2) = inner1 打印'd1'
    @foo2   #执行foo2(f1) =inner2 打印'd2'
    def f1():
        return "我是f1"
    
    ret = f1()
    print(ret)
    
    # f1 = foo2(f1)    --> inner2
    # f1 = foo1(inner2)  --> inner1
    ↓↓
    #执行流程分析:
    #f1()  ==  inner1()->打印'inner1'->return "<i>{}</i>".format(inner2())
    #inner2() -> 打印'inner2'->return "<b>{}</b>".format(f1())
    #f1() -> return "我是f1"
    ↓↓
    print(ret) ---> '<i><b>我是f1</b></i>'

      5.装饰器修复技术  ****

    # 装饰器修复技术
    from functools import wraps
    
    # Flask框架的时候用得上
    
    
    def wrapper(func):
        @wraps(func)
        def inner(*args, **kwargs):
            print('这是新功能')
            func(*args, **kwargs)
        return inner
    
    
    @wrapper
    def f1(arg1, arg2):
        """
        这里写这个函数是做什么的
        :param arg1: 这个参数是什么类型的
        :param arg2: 这个参数是什么类型
        :return: None
        """
        print('嘿嘿嘿')
    
    
    print(f1.__doc__)  
    print(f1.__name__)
    #若不修复的话,f1实际是指向inner的内存空间,
    #f1.__doc__ 相当于 inner.__doc__中的内容
    #f1.__name__ 相当于 inner.__name__中的内容

    五,装饰器究极进阶

      1.类装饰器:用类装饰函数

    class D(object):
        def __init__(self, a=None):
            self.a = a
            self.mode = "装饰"
    
        def __call__(self, *args, **kwargs):
            if self.mode == "装饰":
                self.func = args[0]  # 默认第一个参数是被装饰的函数
                self.mode = "调用"
                return self
            # 当self.mode == "调用"时,执行下面的代码(也就是调用使用类装饰的函数时执行)
            if self.a:
                print("欢迎来到{}页面。".format(self.a))
            else:
                print("欢迎来到首页。")
            self.func(*args, **kwargs)
    
    
    
    @D()  # index = D()(index)   先实例化在传入函数  
    def index(name):
        print("Hello {}.".format(name))
    
    
    @D("电影")    # index = D("电影")(index)   先实例化在传入函数  
    def movie(name):
        print("Hello {}.".format(name))
    
    if __name__ == '__main__':
        index('张三')       
        # index('张三') = D()(index)('张三')  
        # D() --> d_obj
        # d_obj(index) -->1. self.func = args[0] =index; 2. self.mode = "调用" 3.return d_obj
        #d_obj() --> self.a = None --> print("欢迎来到首页。")  --> self.func(*args, **kwargs) = index('张三') --> print("Hello张三.")
               
        movie('张三')       # movie('张三') = D("电影")(movie)(张三)  
        # movie('张三') = D()(movie)('张三')  
        # D() --> d_obj
        # d_obj(movie) -->1. self.func = args[0] =movie; 2. self.mode = "调用" 3.return d_obj
        # d_obj() --> self.a = "电影" --> print("欢迎来到电影页。")  --> self.func(*args, **kwargs) = movie('张三') --> print("Hello张三.")
    
    
    
    #执行结果
    
    """
    欢迎来到首页
    hello 张三
    欢迎来到电影页
    hello 张三
    """
    类装饰器

      2.装饰类:使用装饰器,来批量修改被装饰的类的某些方法

    # 定义一个类装饰器
    class D(object):
        def __call__(self, cls):
            class Inner(cls):
                # 重写被装饰类的f方法
                def f(self):
                    print('Hello 张三.')
            return Inner
    
    
    @D()  # C = D()(C)  先实例化再被调用 C = Inner(C)
    class C(object):  # 被装饰的类
        # 有一个实例方法
        def f(self):
            print("Hello world.")
    
    
    if __name__ == '__main__':
        c = C()   #C() = Inner(C)()  --> c = inner_obj
        c.f()  # c.f() -->  inner_obj.f() -->  print('Hello 张三.')
    类装饰器装饰类
  • 相关阅读:
    三种等待时间的区别
    多种测试的测试方法
    测试面试题总结
    自动化过程中定位不到元素时使用等待方法
    账号登录测试,多表查询
    TP商城添加购物车自动化测试
    二十四个球
    老鼠喝药
    购物车测试点
    前后端分页
  • 原文地址:https://www.cnblogs.com/lianyeah/p/9884701.html
Copyright © 2011-2022 走看看