• 迭代器和生成器


     阅读目录

    楔子

    假如有列表 lst = [1,2,3,4],如果想获取列表中的内容,我们有几种方式?

    第一种,可以用索引取值;

    第二种,可以用for循环,但是也存在特殊情况,比如整型不能用来for循环取值,举个例子:

    for i in 123:
        print(i)

    结果:

    TypeError: 'int' object is not iterable
    'int' object is not iterable 意思是: 整型是不可迭代的

    那么,什么是可迭代的呢?
    lst = [1,2]
    print(dir(lst))
    结果:
    ['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__',
    '__getitem__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mul__',
    '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__sizeof__', '__str__',
    '__subclasshook__', 'append', 'clear', 'copy', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort']
    from collections import Iterable
                                 
    l = [1,2,3,4]                
    t = (1,2,3,4)                
    d = {1:2,3:4}                
    s = {1,2,3,4}                
                                 
    print(isinstance(l,Iterable))
    print(isinstance(t,Iterable))
    print(isinstance(d,Iterable))
    print(isinstance(s,Iterable))
    结果:
    True
    True
    True
    True

    结合上述代码,我们可以得出可迭代协议。可迭代协议简单来说,就是内部实现了__iter__方法.

    也就是说,要想可迭代,内部必须要有__iter__方法,那么,__iter__做了什么呢?

    print([1,2].__iter__())
    结果:
    <list_iterator object at 0x00000000027B7198> 

    iterator

    迭代器

    我们又得到了一个新的词语--迭代器。那么,什么是迭代器呢?先来看段代码:

    l = [1,2,3,4]
    res = l.__iter__()
    print(res)
    结果:
    <list_iterator object at 0x00000000024115F8> #iterator 迭代器

    再用dir()查看l和res可实现的方法:
    print(dir(l))
    print(dir(res))

    结果:

    ['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'append', 'clear', 'copy', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort']
    ['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__length_hint__', '__lt__', '__ne__', '__new__', '__next__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__setstate__', '__sizeof__', '__str__', '__subclasshook__']

    再来看在res中,但不在l中的方法:

    print(set(dir(res))-set(dir(l)))

    结果:

    {'__next__', '__length_hint__', '__setstate__'}  #这些就是迭代器中特有的方法。

    我们再来看看迭代器中特有的三种方法的功能。

    print(res.__length_hint__()) # 迭代器中有多少个元素

    结果: 4

    res.__setstate__(2) # 控制迭代器从哪儿开始迭代

    for i in res:

      print(i)

    结果:

    3
    4

    print(res.__next__()) # 从迭代器中取下一个值

    print(res.__next__())

    print(res.__next__())

    print(res.__next__())

    结果:

    1
    2
    3
    4

     那么,迭代器方法中能够实现一个一个取值的是什么?就是__next__

    for循环,就是在内部调用了__next__从而实现了一个一个取值.

    所以,迭代器遵循迭代协议:必须拥有__iter__和__next__方法

    迭代器的特点:

    1,具有iter和next方法;

    2,通过多次执行next就可以获得迭代器中的所有的值;

    3,迭代器中的值只能取一次

    4,不取的时候值不出现

    迭代器的优点就是:节省内存

     关于迭代器的分析就到这里了,最后,我们再来分析一下,range()是不是一个迭代器呢?

    print('__iter__' in dir(range(5)))
    print('__next__' in dir(range(5)))
    print('__next__' in dir(range(5).__iter__()))
    from collections import Iterator 
    print(isinstance(range(5),Iterator))

    结果:
    True
    False
    True
    False

    生成器

    Python中提供的生成器:

    1.生成器函数:常规函数定义,但是,使用yield语句而不是return语句返回结果。yield语句一次返回一个结果,在每个结果中间,挂起函数的状态,以便下次重它离开的地方继续执行

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

    生成器函数

     所谓的生成器函数,就是包含了yield关键字的函数。

    那么,生成器有什么好处呢?就是不会一下子在内存中生成太多数据。

    假如我想让工厂给学生做校服,生产2000000件衣服,我和工厂一说,工厂应该是先答应下来,然后再去生产,我可以一件一件的要,也可以根据学生一批一批的找工厂拿。
    而不能是一说要生产2000000件衣服,工厂就先去做生产2000000件衣服,等回来做好了,学生都毕业了。。。

    def produce():
        """生产衣服"""
        for i in range(2000000):
            yield "生产了第%s件衣服"%i
    
    product_g = produce()
    print(product_g.__next__()) #要一件衣服
    print(product_g.__next__()) #再要一件衣服
    print(product_g.__next__()) #再要一件衣服
    num = 0
    for i in product_g:         #要一批衣服,比如5件
        print(i)
        num +=1
        if num == 5:
            break

     

     

     

     

  • 相关阅读:
    Eclipse Plugin for Hadoop
    Hadoop伪分布模式配置
    Hadoop单机模式配置
    20180711-Java Number类
    20180711-Java分支结构 – if…else/switch
    20180709-Java循环结构
    20180708-Java运算符
    20180708-Java修饰符
    20180708-Java变量类型
    20180705-Java对象和类
  • 原文地址:https://www.cnblogs.com/yaraning/p/9909196.html
Copyright © 2020-2023  润新知