• Python_基础_(迭代器,生成器)


    一,迭代器

    1,迭代器协议:对象必须具有一个next方法,执行该方法要么返回迭代中的下一项,要么就引起一个StopInteration异常,以来终止迭代(只能往后走,不能向前进)

     2,可迭代对象:实现迭代器协议的对象(再对象的内部定义一个__iter__()方法)

    问题:for循环的本质就是去遵循迭代器协议去访问对象,for循环可以遍历(字符串,列表,元组,字典,集合,文件对象),那么这些数据类型肯定也是可迭代对象?但定义一个列表L = [1,2,3],中没有L.next方法

    解答:(字符串,列表,元组,字典,集合,文件对象)都不是可迭代对象,只是在进行for循环时,调用了它们内部的__iter__方法,将它们编程可迭代对象

    # __iter__()  __next__()  方法

    test = "hello"
    iter_test = test.__iter__()     # 再字符串test的内部具有__iter__方法
    print(iter_test)                # 一个可迭代对象<str_iterator object at 0x00000226F70325F8>
    print(iter_test.__next__())     # 具有 __next__()  方法,输出 h

    # for循环与__iter__()方法

    l = [1,2,3,4,5]
    for i in l:    # 这一步相当执行了 l.__iter__() 将其转为可迭代对象
        print(i)
    
    # 输出
    1
    2
    3
    4
    5
    ## 注:因为可迭代对象在没有下一个子元素时,会引起StopIteration异常,但在进行for循环是,循结束时不会引起异常,
    ## 因为for循环捕捉到了该异常,停止再次进行循环
    
    # 注:非序列类型不能利用while进行遍历 字典,集合,文件对象(就是无下标),可以利用for循环来遍历
    
    # for 循环就是基于迭代器提供了一个统一的可以遍历所有对象的方法,在遍历之前需要调用对象的__iter__方法将其转换成一个迭代器

    # 用可迭代的方式除去列表中元素的值

    l_list = [1,2,3]
    list_iter = l_list.__iter__()    # 将其变为可迭代对象
    print(list_iter.__next__())    # 取得第一个对象1
    print(list_iter.__next__())    # 取得第二个对象2
    print(list_iter.__next__())    # 取得第三个对象3
    # print(list_iter.__next__()) # 会有报错

    # 内置函数 next()用法

    l = [1,2,3,4,5]
    iter_l = l.__iter__()
    print(next(iter_l))    # 输出第一个值1 
                # next()方法为内置函数,调用next()相当于iter_1.__next__()

    。。。

    二,生成器

    生成器:可以理解为一种数据类型,这种数据类型自动实现了迭代器协议(其它的数据类型需要调用__iter__()  方法),所以生成器为可迭代对象 

    ## Python中的生成器

    1.生成器函数:定义一个普通的函数,但是函数不利用return返回结果,而是利用  yield  语句来返回结果

    2.yield 一次只返回一个结果,在每个结果的中间,挂起函数的状态,以便下次执行

    3.生成器表达式:与列表的推导类似,但是,生成器按需产生结果的一个对象,而不是一次构建一个结果列表

    4.生成器的优点:使用生成器对延迟操作提供支持,所谓的延操作指再需要的时候才产生结果,而不是立即产生结果

    # 生成器小结:

    1,可迭代对象

    2,实现延迟计算,节省内存

    3,生成器和其它的数据类型一样,都是实现了迭代器协议,但生成器附加了一个延迟计算省内存的,其它的可迭代对象没有

    ## 生成器函数

    def test():
        yield 1  # 返回一个值 可以填入各种形式的值
        yield 2
        yield 3
    
    
    g = test()  # 获得生成器,但生成器未运行
    print(g)    # <generator object test at 0x0000025BB0032480>
    print(g.__next__())  # 输出:1     执行生成器
    print(g.__next__())  # 输出:2
    print(g.__next__())  # 输出:3     当返回多个值是这样则不会报错
    print(g.__next__())  # 报错 抛出异常:StopIteration

    # 生成器只能遍历一次

    def test():
        for i in range(4)
        yield i
    t = test()    # 获得生成器,但生成器未运行
    
    for i in t:
        print(i)    # 对生成器进行迭代
    
    for i in t:
        print(i)    # 输出为空,因为生成器最多只能迭代一次 

    # 生成器例子

    # 员工工资表.txt
    {"position":"老板","salary":"1"}
    {"position":"秘书","salary":"10000"}
    {"position":"文员","salary":"10000"}
    {"position":"工程师","salary":"100000"}
    {"position":"经理","salary":"10000"}
    
    def get_salary(filename):
        with open(filename) as f:
            for line in f:
                s = eval(line)
                yield s["salary"]
                
    res = get_salary("员工工资表.txt")
    
    all_salary = sum(res)
    for i in res:
        print(p)
        
    # 当执行for循环时,将不会有任何的输出,因为生成器只执行一次,在执行sum语句时。就遍历了生成器,当在for循环语句时,再次遍历生成器时,将不会取到任何值

    ....

    三,三元表达式
    name = "henry"
    res = "hello" if name == "henry" else "hi"
    res = print("名字为henry") if name == "henry" else print("名字不为henry")
    # 当名字为henry时 执行"hello"
    # 当名字不为henry时 执行hi
    # res为取得的返回值

     ....

    四,列表解析
    hot_spicy_pot = []
    for i in range(10):
        hot_spicy_pot.append("吃%s份麻辣香锅" %i)
    print(hot_spicy_pot)
    # ['吃0份麻辣香锅', '吃1份麻辣香锅', '吃2份麻辣香锅', '吃3份麻辣香锅', '吃4份麻辣香锅', '吃5份麻辣香锅', '吃6份麻辣香锅', '吃7份麻辣香锅', '吃8份麻辣香锅', '吃9份麻辣香锅']
    
    # 三元表达式
    hot_spicy_pot = []
    [hot_spicy_pot.append("吃%s份麻辣香锅" %i) for i in range(10)]
    print(hot_spicy_pot)
    # ['吃0份麻辣香锅', '吃1份麻辣香锅', '吃2份麻辣香锅', '吃3份麻辣香锅', '吃4份麻辣香锅', '吃5份麻辣香锅', '吃6份麻辣香锅', '吃7份麻辣香锅', '吃8份麻辣香锅', '吃9份麻辣香锅']
    
    hot_spicy_pot = []
    [hot_spicy_pot.append("吃%s份麻辣香锅" %i) for i in range(10) if i > 5]
    print(hot_spicy_pot)
    # ['吃6份麻辣香锅', '吃7份麻辣香锅', '吃8份麻辣香锅', '吃9份麻辣香锅']

    # 如果当处理的数据较大时,若将所处理的数据全部放于内存中(例如构建一个较大的列表时),会比较占内存

    ### 所以就有了生成器表达式

    # 生成器表达式(将列表解析中的中括号改成小括号)

    列表解析:["吃%s份麻辣香锅" %i for i in range(10) ]
    生成器表达式:("吃%s份麻辣香锅" %i for i in range(10))
    # 列表解析
    hot_spicy_pot = []
    res = [hot_spicy_pot.append("吃%s份麻辣香锅" %i) for i in range(10)]
    print(hot_spicy_pot)
    print(res)      # 无意义 [None, None, None, None, None, None, None, None, None, None]
    
    # 生成器表达式
    hot_spicy_pot = []
    res = ("吃%s份麻辣香锅" %i for i in range(10))
    print(hot_spicy_pot)    # []
    print(res)          # <generator object <genexpr> at 0x0000018945032480>  可迭代对象
    print(res.__next__())   # 吃0份麻辣香锅
    print(next(res))        # 吃1份麻辣香锅

    # 总结:

    1.列表解析和生成器表达式都是一种遍历的编程方式,但生成器表达式更节省内存

    # 例:当计算一个较大的列表时,需要将其先加载到内存中,所以会占用较大的内存,可以用下列的方法解决

    sun(i for i in range(10000000000000000000))

    。。。。

    五,程序的并发操作
    # send(self,value)方法
    
    def test():
        print("开始啦")
        first = yield 1
        print("第一次",first)  # 输出的为 None
        yield 2
        print("第二次")
    
    
    t = test()
    res = t.__next__()
    t.send(None)    # value可以为任何值    
    # 注:执行完上一次的__next__(),当前的执行位置位于yield后,当执行send(None)时,将None的值赋值给first
    ##注:yield相当于return控制的函数的返回值
    # x = yield的另一个特性,接收传过来的值,赋值给x

     # 吃包子模拟单线程

    def consumer(name):
        print("我是[%s],我准备开始吃包子了"%name)
        while True:
            baozi = yield
            print("%s很开心的把{%s}吃掉了"%(name,baozi))
    
    def producer():
        c1 = consumer("henry")
        c1.__next__()
        for i in range(10)
            c1.send("韭菜包子馅")

    。。。。

    六,总结
  • 相关阅读:
    #考研碎碎念#
    #考研笔记#计算机之病毒
    #考研笔记#计算机之多媒体应用
    #考研笔记#计算机之PPT问题
    第六章深入理解类
    第五章方法
    类的基本教程
    类型存储变量
    C#和.net框架
    C#编程概述
  • 原文地址:https://www.cnblogs.com/Doaoao/p/10133602.html
Copyright © 2020-2023  润新知