zoukankan      html  css  js  c++  java
  • 装饰器,迭代器,生成器

    一、装饰器

    无参装饰器的实现

    如果想为下述函数添加统计其执行时间的功能

    import time
    
    def index():
        time.sleep(3)
        print('Welcome to the index page’)
        return 200
    index() #函数执行
    

    闭包函数的方案:

    import time
    
    def index():  # index = 被装饰对象index函数的内存地址
        time.sleep(1)
        print('from index')
    
    def outter(func):  # func = 被装饰对象index函数的内存地址
        def wrapper():
            start = time.time()
            func()  # 被装饰对象index函数的内存地址()
            stop = time.time()
            print('run time is %s' %(stop - start))
        return wrapper  # 千万别加括号
    
    index = outter(index)  # outter(被装饰对象index函数的内存地址) -> 返回wrapper函数的内存地址---> index = wrapper函数的内存地址
    print(index)
    index()
    

    无参装饰器的方案,将wrapper伪装成被装饰的函数,那么应该装的尽可能像一些:

    import time
    def index():  # index = 被装饰对象index函数的内存地址
        time.sleep(1)
        print('from index'
    def home(name):
        time.sleep(2)
        print("welcome %s to home page" %name)
        return 123
    def outter(func):  # func = 被装饰对象index函数的内存地址
        def wrapper(*args,**kwargs):
            start = time.time()
            res = func(*args,**kwargs)  # 被装饰对象index函数的内存地址(x,y,z)
            stop = time.time()
            print('run time is %s' %(stop - start))
            return res
        return wrapper  # 千万别加括号
    index = outter(index)  # outter(被装饰对象index函数的内存地址) -> 返回wrapper函数的内存地址---> index = wrapper函数的内存地址
    home = outter(home)
    # print(index)
    res = home("egon")  # wrapper("egon")
    print(res)
    res = index()  # wrapper()
    print(res)
    

    装饰器的语法糖。被装饰函数的正上方,单独一行

    mport time
    from functools import wraps
    
    def outter(func):  # func = 被装饰对象index函数的内存地址
        @wraps(func)
        def wrapper(*args,**kwargs):
            start = time.time()
            res = func(*args,**kwargs)  # 被装饰对象index函数的内存地址(x,y,z)
            stop = time.time()
            print('run time is %s' %(stop - start))
            return res
        return wrapper  # 千万别加括号
    
    @outter  # index = outter(index)  # outter(被装饰对象index函数的内存地址) -> 返回wrapper函数的内存地址---> index = wrapper函数的内存地址
    def index():  # index = 被装饰对象index函数的内存地址
        """这是index函数"""
        time.sleep(1)
        print('from index')
    
    @outter  # home = outter(home)
    def home(name):
        time.sleep(2)
        print("welcome %s to home page" %name)
        return 123
    
    # res = home("egon")  # wrapper("egon")
    # print(res)
    
    # res = index()  # wrapper()
    # print(res)
    
    print(index.__name__)
    print(index.__doc__)
    

    无参装饰器的模板

    def outter(func):
        def wrapper(*args,**kwargs):
            res = func(*args,**kwargs)
            return res
        return wrapper
    @outter
    def index():
        print('index')
    
    index()
    

    以登录功能为案例:

    def login(func):
        def wrapper(*args,**kwargs):
            name = input('username>>>: ').strip()
            pwd = input('password>>>: ').strip()
            if name == 'egon' and pwd == "123":
                res = func(*args,**kwargs)
                return res
            else:
                print('账号密码错误')
        return wrapper
    @login
    def index():
        print('index')
    
    index()
    

    叠加多个装饰器

    1、加载顺序(outter函数的调用顺序):自下而上

    2、执行顺序(wrapper函数的执行顺序):自上而下

    def deco1(func1):  # func1 = wrapper2的内存地址
        def wrapper1(*args,**kwargs):
            print('==========>wrapper1')
            res1 = func1(*args,**kwargs)
            print('end1')
            return res1
        return wrapper1
    
    def deco2(func2):  # func2 = wrapper3的内存地址
        def wrapper2(*args,**kwargs):
            print('==========>wrapper2')
            res2 = func2(*args,**kwargs)
            print('end2')
            return res2
        return wrapper2
    
    def deco3(func3):  # func3 = 被装饰的index的内存地址
        def wrapper3(*args,**kwargs):
            print('==========>    wrapper3')
            res3 = func3(*args,**kwargs)
            print('end3')
            return res3
        return wrapper3
    
                                    # index = wrapper1的内存地址
    @deco1  # deco1(wrapper2的内存地址) -> wrapper1的内存地址
    @deco2  # deco2(wrapper3的内存地址) -> wrapper2的内存地址
    @deco3  # deco3(被装饰的index的内存地址) -> wrapper3的内存地址
    def index():
        print('index...')
    
    index()
    

    二、迭代器

    1、迭代器的概念:迭代器指的是迭代取值的工具,迭代就是一个重复的过程,但是每一次重复都是在上一次的基础之上进行的,而每一次迭代得到的结果会作为下一次迭代的初始值,单纯的重复并不是迭代

    2、为何要有迭代器?什么是可迭代对象?什么是迭代器对象?

    #1、为何要有迭代器?
    对于序列类型:字符串、列表、元组,我们可以使用索引的方式迭代取出其包含的元素。但对于字典、集合、文件等类型是没有索引的,若还想取出其内部包含的元素,则必须找出一种不依赖于索引的迭代方式,这就是迭代器
    
    #2、什么是可迭代对象?
    可迭代对象指的是内置有__iter__方法的对象,即obj.__iter__,如下
    'hello'.__iter__
    (1,2,3).__iter__
    [1,2,3].__iter__
    {'a':1}.__iter__
    {'a','b'}.__iter__
    open('a.txt').__iter__
    
    #3、什么是迭代器对象?
    可迭代对象执行obj.__iter__()得到的结果就是迭代器对象
    而迭代器对象指的是即内置有__iter__又内置有__next__方法的对象
            调用迭代器对象的__iter__方法得到的它自己,就跟没调用一样
            调用迭代器对象的__next__方法返回下一个值,不依赖索引
            可以一直调用__next__直到取干净,则抛出异常StopIteration
    
    文件类型是迭代器对象
    open('a.txt').__iter__()
    open('a.txt').__next__()
    
    #4、注意:
    迭代器对象一定是可迭代对象,而可迭代对象不一定是迭代器对象
    

    for 循环迭代

    nums_iter = iter(nums)
    while True:
        try:
            res = next(nums_iter)
            print(res)
        except StopIteration:
            break
    
    1、先调用in后那个对象的__iter__方法,拿到迭代器对象
    2、 res = next(迭代器对象),执行一次循环体代码
    3、循环往复步骤2,直到值取干净抛出异常StopIteration,for会捕捉异常结束循环
    for res in nums:
        print(res)
        
      #基于for循环,我们可以完全不再依赖索引去取值了
    dic={'a':1,'b':2,'c':3}
    for k in dic:
        print(dic[k])
    
    #for循环的工作原理
    #1:执行in后对象的dic.__iter__()方法,得到一个迭代器对象iter_dic
    #2: 执行next(iter_dic),将得到的值赋值给k,然后执行循环体代码
    #3: 重复过程2,直到捕捉到异常StopIteration,结束循环
    

    迭代器的优缺点

    #优点:
      - 提供一种统一的、不依赖于索引的迭代方式
      - 惰性计算,节省内存
    #缺点:
      - 无法获取长度(只有在next完毕才知道到底有几个值)
      - 一次性的,只能往后走,不能往前退
    

    三、生成器

    1、什么是生成器

    #只要函数内部包含有yield关键字,那么函数名()的到的结果就是生成器,并且不会执行函数内部代码,得到的返回值即生成器对象
    
    def func():
        print('====>first')
        yield 1
        print('====>second')
        yield 2
        print('====>third')
        yield 3
        print('====>end')
    
    g=func()
    print(g) #<generator object func at 0x0000000002184360>
    
    有了yield关键字,我们就有了一种自定义迭代器的实现方式。yield可以用于返回值,但不同于return,函数一旦遇到return就结束了,而yield可以保存函数的运行状态挂起函数,用来返回多次值。yield的总结
    1、把函数做成迭代器
    2、对比return,可以返回多次值,可以挂起/保存函数的运行状态
    

    2、生成器就是迭代器

    生成器内置有__iter__和__next__方法,所以生成器本身就是一个迭代器
    g.__iter__
    g.__next__
    生成器就是迭代器,因此可以这么取值
    res=next(g)
    print(res)
    
  • 相关阅读:
    javascript和C#比较
    前端模块管理器简介
    javascript中的splice方法介绍&示例
    javascript中数组揭秘
    17款code review工具
    IIS ip访问限制插件
    iis 限制动态IP地址访问次数
    AWS云使用100条宝贵经验分享
    C# 开源框架(整理)
    如何获取Azure AD tenant的tenant Id?
  • 原文地址:https://www.cnblogs.com/caodan01/p/14211703.html
Copyright © 2011-2022 走看看