• Python 全栈开发五 迭代器 生成器 装饰器


    一、迭代器

    迭代协议:对象必须提供一个next方法,执行该方法后会返回迭代的下一项或者抛出Stopiteration异常,终止迭代。切只能往前,不能倒退。

    可迭代对象:遵循迭代协议的对象就是可迭代对象。

    迭代器是一个可以记住遍历的位置的对象。迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。迭代器只能往前不会后退。

    迭代器有两个基本的方法:iter() 和 next()

    字符串,列表或元组对象都可用于创建迭代器,生成迭代器的方法是iter():

    1 li = [1,2,3,4]
    2 #inter()本质调用了内置的__iter__
    3 a = li.__iter__()  #生产一个可迭代对象
    4 #next()本质调用__next__()
    5 a.__next__()       #对可迭代对象进行取值

    方法二:

    >>li = [1,2,3,4,5]
    >>it = iter(li)     #生成一个迭代器
    >>it.__next__()
    1
    >>next(it)  #以上两种next都可以使用
    2
    >>for i in it:
            print(i)
    3
    4
    5
    #迭代完毕后,迭代器里面的数据就没有了
    >> type(it)
    <class 'list_iterator'>   #类型是迭代器类型

     

    二、生成器

    在描述生成器前我们先来了解列表生成式:

    #普通定义的列表直接把列表写死
    li = [1,2,3,4,5]
    
    #使用列表生成式,可以为列表添加一些新的属性
    
    li1 = [a*a for a in range(10)]
    print(li1)
    
    #也可以用以下两种方法方法
    
    li2 = list(map(lambda x:x+1,li))
    print(li2)
    
    
    a = []
    for i in range(10):
        a.append(i+1)
    print(a)
    
    #从以上对比可以看出,使用第二种方法代码最为简单,即列表生成式

      虽然有列表生成式,可以简化生成特定列表的操作,但是当列表数据过大,就会过度的消耗内存,并且列表是数据也不会一直使用,在python中有一种一边循环一边计算的机制就是生成器。

    生成器的第一种表现形式:

    #创建一个生成器
    
    li = (a*a for a in range(10))
    
    print(li) #<generator object <genexpr> at 0x00000000027BD468>,返回一个生成器对象,用next调用对象
    print(li.__next__())
    print(next(li))  #且只能调用一次,不能往回调用
    
    '''我们讲过,generator保存的是算法,每次调用next(g),
    就计算出g的下一个元素的值,直到计算到最后一个元素,没有更多的元素时,
    抛出StopIteration的错误。一般情况下,我们用for循环来调用全部数据'''
    
    for i in li:
        print(i)

    生成器的第二种表现形式:

      生成器:一个函数调用时返回一个迭代器,那这个函数就叫做生成器(generator),如果函数中包含yield语法,那这个函数就会变成生成器 跟普通函数不同的是,生成器是一个返回迭代器的函数,只能用于迭代操作,更简单点理解生成器就是一个迭代器。调用一个生成器函数,返回的是一个迭代器对象。

      yield语法:每当行数运行到yield是就会中断并且保存当前所有的运行信息,并且在执行next()方法后继续从中断的地方运行。

    #生成一个斐波拉契数列
    def fib(max):
        a,b,n = 0,0,1
        while n < max:
            a, b = b,a+b
            n +=1
        return 'done'
    
    c = fib(5)
    print(c)
    #弊端,会直接全部生成
    
    #把该函数变为一个生成器
    def fib2(max):
        a,b,n = 0,0,1
        while n < max:
            yield b    #遇到一次返回一次,再次激活则运行后面的代码,用next激活
            a, b = b,a+b
            n +=1
    
    d = fib2(5)
    print(next(d))

    下面是一个利用yield实现的一种单线程下的并发效果,也可以理解为一协程(后面会讲这一内容):

    import time
    
    def consumer(name):
        print('%s准备吃包子了!' % name)
        while True:
            baozi = yield               # 保存当前状态的值,并且退出函数
            print('包子[%s]来了,被[%s]吃了!'% (baozi,name))
    
    # c = consumer('alix')   生成一个生成器对象
    # c.__next__()        调用生成器
    
    def producer():
        c = consumer('a')
        c2 = consumer('b')
        c.__next__()
        c2.__next__()
        print('老子开始准备做包子了')
        for i in range(10):
            time.sleep(1)
            print('做了1个包子,分两半')
            c.send(i)               #给yield传值,并且唤醒yield
            c2.send(i)
    producer()

    三、装饰器

    装饰器:本质上就是函数,作用就是为其他函数添加其他功能
    原则:1、不能修改被装饰的函数的源代码
    2、不能修改被修饰函数的调用方式

    在将装饰器前我们进行一些装饰器的知识储备:

    1.函数即'变量'
    2.高阶函数
    1.把一个函数名当做实参传给另一个函数(添加功能不修改函数的源代码)
    2.返回值中包含函数名(不修改函数的调用方式)
    3.嵌套函数

    函数即“变量”:

    函数定义好后就像变量一样存储在内存中,当我们去调用的时候才会有意义。

    #函数即变量
    
    # def foo():
    #     print('in the foo')
    # foo()
    
    #即无需考虑函数的定义顺序,就和定义变量一样
    
    def bar():
        print('in the bar')
    def foo():
        print('in the foo')
        bar()
    foo()

    高阶函数:即把一个函数名当做实参传递给函数,就类似有把一个变量名传递给函数。

    # 高阶函数:把一个函数名,当做实参传给函数
    import time
    def bar():
        time.sleep(3)    #暂停3秒
        print('in the bar')
    
    def text1(fun):
        start_time = time.time()   #起始时间
        fun()
        stop_time = time.time()    #结束时间
        print('the fun time is %s' % (stop_time-start_time))  #计算出fun()所用的时间
    
    text1(bar)  #将该函数名传递进去
    
    
    def bar2():
        time.sleep(3)
        print('in the bar2')
    
    def text2(fun):
        print(fun)
        return fun
    
    bar2 = text2(bar2)
    bar2()

    通过高阶函数的作用可以看出:在不改变函数的源代码的情况下,给函数增加了计时的功能

    嵌套函数:

    def foo():
        print('in the foo')
        def bar():
            print('in the bar')
        bar()
    foo()

    结合以上三种实现装饰器:

    import time
    def timer(func): #timer(text1)   func=text1    装饰器函数
        def wrapper(*args,**kwargs):
            start_time = time.time()
            func()              #run text1
            stop_time = time.time()
            print('the fun run time is %s' % (stop_time-start_time))
        return wrapper
    
    @timer   # text1 = timer(text1)  这一步就是把text1传入timer
    def text1():
        time.sleep(1)
        print('the is text1')
    
    text1()

    带参数的装饰器:

    user,passwd = 'alex','1234'
    
    def auth(outh_type):
        print('auth func:',outh_type)
        def outh_wrapper(func):
            def wrapper(*args,**kwargs):
                print('wrapper func args:',*args,**kwargs)
                if outh_type == 'local':
                    username = input('Username:'.strip())
                    password = input('Password:'.strip())
                    if user == username and passwd == password:
                        print('33[32;1mUser has passed authentication33[0m')
                        res = func(*args,*kwargs)
                        print('-- after authentication')
                        return res
                    else:
                        exit("33[31;1mInvalid username or password33[0m")
                elif outh_type == 'ldap':
                    print('搞毛线')
    
            return wrapper
        return outh_wrapper
    
    @auth(outh_type='local')
    def index():
        print('welcom to index page')
    
    index()

     http://www.cnblogs.com/wupeiqi/articles/4980620.html  

     

  • 相关阅读:
    将textarea滚动至底部:
    Web应用程序项目OxiteSite已配置为使用IIS.在本地计算机上找不到服务器
    使用Entity Framework时要注意的一些性能问题
    Python 输入输出
    Python 语言简介
    瞧一瞧,看一看,微信应用号(小程序)
    路遥眼里的河南人<平凡的世界>
    HTML5 本地存储实现购物车功能
    HTML5 本地存储的用法
    网站/域名如何备案?
  • 原文地址:https://www.cnblogs.com/tashanzhishi/p/8860363.html
Copyright © 2020-2023  润新知