• 闭包和装饰器


    一、python闭包

    1、生命周期

    def outer():
        a = 10
        print(f"test {a}")
    outer()
    
    • 1
    • 2
    • 3
    • 4

    2、闭包要满足的条件

    2.1、必须要有内嵌函数
    ​	2.2、内涵数必须要引用外函数的变量
    ​	2.3、外函数必须返回内函数
    	示例:
    		def outer(x):
    		    a = 300
    		    def inner():
    		        print(x+a)
    		    return inner
    		d = outer(100)
    		d()
    		print(dir(d))
    		#形成闭包之后,闭包函数就会得到一个非空的__closure__属性
    		print(outer.__closure__,d.__closure__)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    3、用闭包实例化的对象
    .虽然代码都一样,但是创建的对象是不一样的,每次调用外函数都会重新执行,创建一个新的tmp_list和inner

    def outer():
        tmp_list = []
        def inner(name):
            tmp_list.append(name)
            print(tmp_list)
        return inner
    d1 = outer()
    d1("d1")
    d1('d1')
    d2 = outer()
    d2('d2')
    d2("d2")
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    二、装饰器

    1、装饰器的介绍

    1.是一种程序设计模式,不改变函数或类的源代码基础上,添加额外功能
    2.装饰器的本质就是闭包函数,它需要把一个callable(函数,类)对象作为参数传递进来
    
    • 1
    • 2

    2、引出装饰器

    #为了引出装饰器
    import time
    #时间戳:
    	从1970到现在所经历的秒数
    def func1():
        time.sleep(2)
        print("func1.........")
    
    def func2():
        time.sleep(3)
        print("func2.........")
    start = time.time()
    func1()
    end = time.time()
    print(f"func1执行花了{end - start }秒")
    
    start = time.time()
    func2()
    end = time.time()
    print(f"func2执行花了{end - start }秒")
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    3、统计运行时间的装饰器

    #除了主功能之外还实现了其他功能
    import time
    def runtime(func):
        def inner(*args,**kwargs):
            start = time.time()
            result = func(*args,**kwargs)	#让装饰器更加通用
            end = time.time()
            print(f"执行函数花了{end - start}秒")
            return result
        return inner
    # @ 修饰符,去使用装饰器
    @runtime    #func1 = runtime(func1)
    def func1():
        time.sleep(2)
        print("func1.........")
        return "sanchuang"
    @runtime
    def func2(a,b):
        time.sleep(3)
        print("func2.........")
        print(f"fun2...{a}{b}")
    
    result = func1()
    print(result)
    func2(1,2)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    4、用装饰器实现权限控制

    import functools
    import time
    def deco(name):
        def runtime(func):
            #保留传递进来的函数的原数据,将它的原数据赋值给inner
            @functools.wraps(func)
            def inner(*args,**kwargs):
                if name=="root":
                    print("欢迎")
                    print(f"func name is {func.__name__}")
                    result = func(*args,**kwargs)
                    return result
                else:
                    return "没有权限"
            return inner
        return runtime
    
    username = input("请输入你的用户名:")
    @deco(name=username)
    def add(a,b):
        time.sleep(3)
        return a+b
    print(add(1,2))
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    三、装饰器的应用

    1、可以应用多个装饰器去装饰函数,但是要注意装饰器的执行顺序
    2、添加额外功能:计时、权限控制、日志记录等
    3、案例:

    import functools
    import time
    def runtime(func):
        #保留传递进来的函数的原数据,将它的原数据赋值给inner
        @functools.wraps(func)
        def inner(*args,**kwargs):
            start = time.time()
            result = func(*args,**kwargs)
            end = time.time()
            print(f"函数执行花了{end - start}s")
            return result
        return inner
    
    def login_required(func):
        username = input("请输入你的用户名:")
        def inner(*args,**kwargs):
            if username=='root':
                print(f"欢迎执行{func.__name__}函数")
                result = func(*args,**kwargs)
                return result
            else:
                return "没有权限"
        return inner
    
    @login_required
    @runtime
    def add(a,b):
        time.sleep(2)
        return a+b
    result = add(1,2)
    print(result)
    
    @login_required
    @runtime
    def add2(a,b):
        time.sleep(3)
        return a+b
    result1 = add2(1,2)
    print(result1)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    四、带参数的装饰器

    1、自身不传入参数的装饰器,使用两层函数定义
    2、自身传入参数的装饰器,使用三层函数定义

    import functools
    import time
    def deco(name):
        def runtime(func):
            #保留传递进来的函数的原数据,将它的原数据赋值给inner
            @functools.wraps(func)
            def inner(*args,**kwargs):
                start = time.time()
                result = func(*args,**kwargs)
                end = time.time()
                print(f"函数执行花了{end - start}s")
                print(f"name is {name}")
                return result
            return inner
        return runtime
    
    # runtime = deco(name = "sanle")
    # func1 = runtime(func1)
    @deco(name="sanle")
    def func1():
        time.sleep(3)
        print("this is func1")
    func1()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    3、练习

    	​装饰器带参数,来验证用户是否有权限运行函数
    	运行add函数,运行前要判断有没有权限
    ​	判断一:用户名和密码是否正确			---用户名错误或密码错误
    ​	判断二:用户名是否为root,只有root用户有权限   		----输出用户没有权限
    ​	用户名和密码 通过带参传入
    
    • 1
    • 2
    • 3
    • 4
    • 5
    import functools
    import time
    def deco(name):
        def runtime(func):
            #保留传递进来的函数的原数据,将它的原数据赋值给inner
            @functools.wraps(func)
            def inner(*args,**kwargs):
                if name=="root":
                    print("欢迎")
                    print(f"func name is {func.__name__}")
                    result = func(*args,**kwargs)
                    return result
                else:
                    return "没有权限"
            return inner
        return runtime
    
    username = input("请输入你的用户名:")
    @deco(name=username)
    def add(a,b):
        time.sleep(3)
        return a+b
    print(add(1,2))
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    五、属性包装 装饰器----property

    property:把方法当作属性来使用

    class Person():
        _age = 2
        @property   #property本身会创建另外两个装饰器,@age.setter  @age.deleter
        def age(self):
            return self._age
        @age.setter
        def age(self,num):
            if 0< num <120:
                self._age = num
            else:
                raise  ValueError("年龄不在范围")
    p = Person()
    print(p.age)
    p.age = 110
    print(p.age)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    六、用类去实现装饰器

    1、不带参数的装饰器用类实现

    import time
    class runtime:
        def __init__(self,func):
            self.func = func
        def __call__(self,*args,**kwargs):
            start = time.time()
            result = self.func(*args,**kwargs)
            end = time.time()
            print(f"运行函数{self.func.__name__}花费了{end - start}秒")
            return result
    
    @runtime
    def func1(a,b):
        print("this is func1......")
        time.sleep(2)
        return a+b
    print(func1(1,2))
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    2、带参数的装饰器用类实现

    import time
    class runtime:
        def __init__(self,name):
            self.name = name
        def __call__(self,func):
            def deco(*args,**kwargs):
                start = time.time()
                result = func(*args,**kwargs)
                end = time.time()
                print(f"运行函数{func.__name__}花费了{end - start}秒")
                return result
            return deco
    
    @runtime("name")
    # a1 = runtime("name")
    # func1 = a1(func1)
    def func1():
        time.sleep(2)
        print("this is func1......")
    
    func1()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    七、装饰类

    def outer(cls):
        def inner(*args,**kwargs):
            print(f"class name is:{cls.__name__}")
            return cls(*args,**kwargs)
        return inner
    
    @outer  # A = outer(A)
    class A:
        def __init__(self,name):
            self.name = name
    print(type(A))
    m = A("sc")
    print(m.name)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
  • 相关阅读:
    Html- 阻止子元素事件触发父元素事件(事件冒泡)
    linux三次握手、四次挥手
    hadoop2-hive
    Xinlinx zynq7010国产替代 FMQL10S400 全国产化 ARM 核心板+扩展板
    嬴彻科技日: 发布《自动驾驶卡车量产白皮书》分享从量产走向无人技术路线
    雷神MixBook Air笔记本系统故障怎么重装?
    大数据第二章Hadoop习题
    2022年最新《谷粒学院开发教程》:9 - 前台课程模块
    Chapter7.2线性离散系统的分析与校正
    【打卡】牛客网:BM45 滑动窗口的最大值
  • 原文地址:https://blog.csdn.net/weixin_47661174/article/details/126062922