zoukankan      html  css  js  c++  java
  • 闭包&装饰器

    闭包条件

    • 作用域 L_E_G_B
    • 函数中嵌套函数
    • 外层函数返回内存嵌套函数名
    • 嵌套函数有引用一个非全局据变量(E作用域)
    def func():
        a = 100  # Enclosed作用于
    
        def inner():
            print(a)
    
        return inner
    
    
    f = func()
    print(f)  # 返回inner函数对象
    f()  # 执行inner函数
    

    作用:实现数据锁定,提高稳定性

    装饰器

    • 知识储备:

      • 作用域 L_E_G_B
      • 高阶函数 :1.函数名可以作为参数传入;2.函数名还可以作为返回值
      • 闭包
    • 解释:

      • 装饰函数是一个闭包样式的函数,参数是被装饰函数
      • 被装饰函数会当作参数传入装饰函数中,然后返回给被装饰函数接收,所以我们执行被装饰函数的时候就等于执行装饰器函数的返回值--嵌套函数
    • 目的:遵循原则,开放扩展 关闭修改

    • 好处

      • 在不改变原函数功能的情况扩展功能
      • 执行原函数就能执行到扩展功能
    • 装饰器的应用场景

      • 登陆验证
      • 函数运行时间统计
      • 执行函数之前做准备工作
      • 执行函数后做清理功能
    # 添加时间统计的装饰器
    def add_time(func):
        # *args, **kwargs作用:有参数无参数的函数都能装饰 
        def inner(*args, **kwargs):
            before_time = time.time()
            func(*args, **kwargs)
            after_time = time.time()
            print(after_time - before_time)
    
        return inner
    
    
    @add_time
    def for_fun():  # for_fun=add_time(for_fun)   add_time(for_fun) == inner 
        for i in range(100):
            if i == 50:
                time.sleep(1)
                print(i)
    
    
    # 所以执行for_fun的时候等于执行的inner
    for_fun()
    
    # 登陆验证的装饰器,每个页面验证登陆 如果登陆过不需要重复登陆
    # txt数据
    # {"name":"a","passwd":"1"}
    # {"name":"b","passwd":"2"}
    # {"name":"c","passwd":"3"}
    
    cookie = "False"
    def check_login(func):
        def inner(*args, **kwargs):
            global cookie
            if cookie == "False":
                print("身份验证失败请重新登陆")
                n = 0
                while n < 4:
                    username = input("请输入你的用户名").strip()
                    passwd = input("请输入你的密码").strip()
                    # 读取用户信息文件,判断帐号密码
                    with open("login_info.txt", "r", encoding="utf-8") as file:
                        for line_info in file:
                            user_info = eval(line_info.strip())
                            if username == user_info["name"] and passwd == user_info["passwd"]:
                                print("登陆成功")
                                cookie = "True"
                                func(*args, **kwargs)
                            
                        else:
                            print("用户名不存在或密码错误")
                            n += 1
                else:
                    print("错误次数过多,退出登陆")
            else:
                func(*args, **kwargs)
               
        return inner
    
    
    @check_login
    def home():
        print("欢迎来到首页")
    
    
    @check_login
    def me():
        print("欢迎来到个人中心")
    
    
    print(home())
    print(me())
    
    
    • 装饰器装饰类
      • 将类对象传进装饰器,逻辑和装饰函数一样
      • 嵌套函数需要返回类实例对象
    # 类装饰器,reture 实例对象即可
    def Myfunc(cls):
        def inner(*args, **kwargs):
            print("进入装饰器")
            # cls是传进来的类 被执行实例化对象,初始化实例对象初始值
            # # 必须将对象返回给调用方接收实例
            return cls(*args, **kwargs)
    
        return inner
    
    
    @Myfunc
    class MyClass:  # MyClass=Myfunc(MyClass)
        def __init__(self, name, age):
            self.name = name
            self.age = age
    
    
    # 实例化对象是执行装饰器内层函数后 返回的一个实例对象给m接收
    m = MyClass("DaBai", 18)
    print(m)  # <__main__.MyClass object at 0x000001E76D6A0358> 实例对象 
    print(m.name)
    
    

    类中常用的三个装饰器

    • @classmethod 标记为类方法,默认参数为"cls",类本身可以直接调用(类属性,类方法,类本身和实例都可以直接调用,实例属性和实例方法,类本身不能调用,所以将方法加上@classmethod 装饰器变成类方法后类本身就可以直接调用了)
    • @staticmethod 标记为静态方法,默认不需要传参,类和实例都能调用
    • @property 设置只读属性,被property装饰的方法可以像属性一样被实例调用,但是属性值为只读属性,不能被修改(毕竟原始还是个方法)
    # 三个类装饰器
    class MyTest(object):
    
        def __init__(self, name):
            self.name = name
    
        @classmethod  # 类方法
        def add(cls):  # 默认参数传cls==类本身,self==实例本身
            print("add方法")
            # print(cls)
    
        @staticmethod  # 静态方法 类本身和实例对象都能调用
        def static():  # 默认不需要传参数,不像类方法默认传cls,实例方法默认传self
            print("这个是静态方法")
    
        @property  # 作用:设置实例的只读属性,不允许被修改 ,不允许修改的属性这样设置
        def Name(self):
            print("被这个装饰的类方法,可以像是属性一样被调用")
            name = "pro"
            return name
    
        def run(self):
            print(self.name)  # 实例属性 name 可以修改
            print(self.Name)  # 被@property装饰的方法可以像属性一样调用,不可被修改
    
    
    # 实例
    t = MyTest("DaBai")
    
    # 类方法(classmethod)
    MyTest.add()  # 类直接调用
    t.add()  # 实例也能调用
    
    # 静态方法(staticmethod)
    MyTest.static()  # 类直接调用
    t.static()  # 实例也能调用
    
    # 只读方法(property)实例方法可以像属性一样调用
    # 实例属性允许被修改或者添加
    print(t.name)
    t.name = "Bai"
    print(t.name)
    
    # property  设置只读属性不允许被修修
    # t.Name = "PRO"  # 报错:AttributeError: can't set attribute
    print(t.Name)  # 被property装饰的方法可以像属性一样调用 但是属性值为只读属性,不能被修改(毕竟原始还是个方法)
    
    t.run()
    
    
  • 相关阅读:
    python中的编码问题
    CVPR2018 Tutorial 之 Visual Recognition and Beyond
    hdu 1376 Octal Fractions
    hdu 1329 Hanoi Tower Troubles Again!
    hdu 1309 Loansome Car Buyer
    hdu 1333 Smith Numbers
    hdu 1288 Hat's Tea
    hdu 1284 钱币兑换问题
    hdu 1275 两车追及或相遇问题
    hdu 1270 小希的数表
  • 原文地址:https://www.cnblogs.com/jiangmingbai/p/10903617.html
Copyright © 2011-2022 走看看