zoukankan      html  css  js  c++  java
  • 叠加装饰器与迭代器

    一、叠加装饰器

    在同一个被装饰对象中,添加多个装饰器,并执行,模板:

    1 模板:
    2         @装饰器1
    3         @装饰器2
    4         ...
    5         def 被装饰对象():
    6             pass

    注意:装饰器在调用被装饰对象时才会执行添加的功能

    - 叠加装饰器:
      - 装饰的顺序: 由下到上装饰
      - 执行的顺序: 由上往下

    注意: 无论inner中出现任何判断,最后都要返回“调用后的被装饰对象” func(*args, **kwargs)

    # 需求: 为被装饰对象,添加统计时间 与 登录认证功能
    import time
    
    # 定义一个全局变量,表示用户是否验证通过
    login_info = {
        'login': False
    }
    
    # 登录功能
    def login():
        # 判断用户没有登录时,执行登录功能
        name = input("username:").strip()
        pwd = input('password:').strip()
        if name == 'abc' and pwd == '123':
            print('登录成功!')
            login_info['login'] = True
        else:
            print('登录失败!')
    
    # 登录认证装饰器
    def login_auth(func):
        def inner1(*args, **kwargs):
            """
            注意: 无论inner中出现任何判断,
            最后都要返回“调用后的被装饰对象” func(*args, **kwargs)
            """
            if login_info.get('login'):
                res = func(*args, **kwargs)
                return res
            else:
                login()
                return func(*args, **kwargs)
        return inner1
    
    # 统计时间装饰器
    def time_record(func):
        def inner2(*args, **kwargs):
            print('开始统计')
            start_time = time.time()
            res = func(*args, **kwargs)
            end_time = time.time()
            print(end_time - start_time)
            return res
        return inner2
    
    
    # 下载电影功能
    """
    - 叠加装饰器:
            - 装饰的顺序: 由下到上装饰
            - 执行的顺序: 由上往下
    """
    @time_record    # inner2 = time_record(inner1地址)
    @login_auth     # inner1 = login_auth(func)
    # @time_record
    def func():
        print('start')
        time.sleep(2)
        print('end')
    
    func()
    # login()
    # 执行的顺序: 先执行time_ record功能,再执行login_auth功能
    # 统计登录时间 + 下载时间
    # func()
    
    # 装饰顺序
    # @login_auth   # inner1 = login_auth(inner2)
    # @time_record  # inner = time_record(download_movie)
    
    # 执行顺序:
    # 先执行login_auth, 再执行time_record
    # 只统计下载电影的时间
    # login()  # 先调用登录,模拟用户已登录

    二、有参装饰器

    # 无参装饰器: 装饰在被装饰对象时,没有传参数的装饰器。
    '''
    # 以下是无参装饰器
    @wrapper1  # inner1 = wrapper1(inner2)
    @wrapper2  # inner2 = wrapper2(inner3)
    @wrapper3
    '''

    了解无参装饰器后,我们可以再实现一个用来为被装饰器对象添加认证功能的装饰器,需要传入用户级别参数

    # 有参装饰器: 在某些时候,我们需要给用户的权限进行分类
    '''
    # 以下是有参装饰器
    @wrapper1(参数1)  # inner1 = wrapper1(inner2)
    @wrapper2(参数2)  # inner2 = wrapper2(inner3)
    @wrapper3(参数3)
    '''
    # 需求,给登录功能再添加一个可以验证用户级别的功能,传入级别参数
    def user_auth(user_level):      # 'VIP'
        def wrapper(func):
            def inner(*args, **kwargs):
                if user_level == 'VIP':
                    print('VIP用户')
                    res = func(*args, **kwargs)
                    return res
                else:
                    print('普通用户')
                    return func(*args, **kwargs)
            return inner
        return wrapper
    
    # 被装饰对象
    
    # wrapper = user_auth('普通')
    # @wrapper
    # @user_auth('VIP')  # wrapper = user_auth('普通用户')
    # @wrapper  #<--- 返回结果(wrapper) <---- user_auth()
    
    # 有参装饰器的使用
    @user_auth('VIP')
    def func():
        pass
    
    func()

    有参装饰器,最外一层函数参数可以随意添加,所以装饰器对象最多包含三层

    三、wraps

    wraps是一个修复工具,修复的是被装饰对象的空间,使用方法

    from functools import wraps
    
    def wrapper(func):
        @wraps(func)    # 修改名称空间:inner ---> func
        def inner(*args, **kwargs):
            """
            此处是装饰器的注释
            :param args:
            :param kwargs:
            :return:
            """
            res = func(*args, **kwargs)
            return res
        return inner
    
    @wrapper
    def func():
        """
        此处是func函数的注释
        :return:
        """
        pass
    
    # 函数对象.__doc__:查看函数内部的注释
    print(func.__doc__)
    # 结果就是返回func里面的注释

    四、迭代器

    迭代的工具

    迭代:

      迭代指的是重复迭代,每一次迭代都是基于上一次的结果而来的

    迭代器:

      迭代器指的是迭代取值的工具,它可以迭代取值

    可迭代对象:

      凡是内部有str.__iter__()方法的都是可迭代对象。

      可迭代对象有:字符串str、列表list、元组tuple、字典dict、集合set、文件f

    获取迭代器:

      通过可迭代对象.__iter__(), 得到的返回值就是 “迭代器对象”。

      迭代器是迭代取值的工具,作用是迭代取值

    如何迭代取值:

      迭代对象.__next__()  每执行一次,都会从迭代器对象中取出一个值

    str1 = '123456'
    iter_str = str1.__iter__()
    print(iter_str)     # iterator指的是迭代器对象
    print(iter_str.__next__())
    print(iter_str.__next__())
    print(iter_str.__next__())
    print(iter_str.__next__())
    print(iter_str.__next__())
    print(iter_str.__next__())
    
    # 因为迭代器中的值已经取完
    # print(iter_str.__next__())    # 报错StopIteration

    - 总结: 可迭代对象 VS 迭代器对象:
      - 获取可迭代对象: 定义序列类型(str, list, set, tuple, dict, f)
        - 特点:
          内置有__iter__()

      - 获取迭代器对象: 通过可迭代对象调用.__iter__()得到返回值
        - 特点:
          内置有__next__()

    - 迭代器对象的优点:
      - 优点:
        1.不依赖于索引迭代取值。
        2.节省内存空间。

      - 缺点:
        1.取指定某个值麻烦
        2.每次取值都要从第一个值开始,无法同过索引取值。

    当迭代器中的值取完时,继续执行会报错,这里补充一个try语法防止此问题

    list1 = [1,2,3,4]
    iter_list = list1.__iter__()
    while True:
        try:
            print(iter_list.__next__())     # 若不捕获异常,当取完迭代器对象后会报错
        # 当遇到StopIteration异常,会立即执行此处代码
        except StopIteration:
            break

    for循环原理
      语法: for i in 可迭代对象:
      in: 可迭代对象 ----> 内部会自动调用.__iter__() ---> 迭代器对象
      for line in list1:
        # 迭代器对象.__next__()

    # 不依赖于索引取值
    list1 = [1,2,3,4]
    for i in list1:     # list1是可迭代对象 ----> 内部会自动调用.__iter__() ---> 迭代器对象
        # 迭代器对象.__next__()
        print(i)
    # 依赖于索引取值
    list1 = [1,2,3,4]
    n = 0
    while n < len(list1):
        print(list1[n])
        n += 1

    迭代器本质上是一个可迭代对象

    文件本质上既是迭代器对象,也是可迭代对象。

    # 唯独文件比较特殊: 因为文件从读取出来的时候就是一个迭代器对象
    # f ---> 可迭代对象, 还是迭代器对象
    # 文件既是可迭代对象,也是迭代器对象。
    f = open('test.txt','r',encoding='utf-8')
    iter_f = f.__iter__()
    print(iter_f is f)      # True

    可迭代对象不一定是迭代器对象

    set1 = {1,2,3,4}
    
    iter_set1 = set1.__iter__()
    iter_set1.__next__()
    
    # 迭代器对象也是一个可迭代对象
    # 判断可迭代对象是否是迭代器对象
    print(iter_set1.__iter__() is iter_set1)    # True
    print(iter_set1 is set1)        # False
    # 可迭代对象不一定是迭代器对象
  • 相关阅读:
    IIS: 必须输入密码手动设置密码同步后
    IIS操作控制类
    SQL对IP地址进行拆分
    HTTP_REFERER的工作方式[转贴]
    如何知道同服务器上都有哪些网站?
    简单判断临时表是否存在
    .NET 3.5 SP 1发布了
    Log Parser很好很强大的IIS日志分析工具
    遍历Request.ServerVariables
    06复杂查询(多数据库表)
  • 原文地址:https://www.cnblogs.com/hexianshen/p/11851596.html
Copyright © 2011-2022 走看看