zoukankan      html  css  js  c++  java
  • Python Iterables Iterators Generators

    container

    某些对象包含其它对象的引用,这个包含其它对象引用的对象叫容器.例如list可以包含int对象,或者由其它数据类型(或数据结构)的对象组成一个list.
    对其他对象的引用是容器值的一部分,如果这个引用是对可变对象的引用,那么这个可变对象值改变的时候,容器中的值也会变

    Iterables

    一次可以返回一个成员的对象,就是可迭代对象.
    任何实现了__iter__()方法或有__getitem__()方法实现序列语义的类的对象.
    序列(sequence):一个支持使用整形索引(indices)利用 getitem()实现元素访问并且定义了可以返回序列长度的__len__()方法的可迭代对象.典型内置:list, str, tuple, and bytes.
    可迭代对象可以使用在for循环或者在许多其它需要一个序列的地方(如zip().map()...).
    当可迭代对象做为参数传给内置iter()函数时,它会返回一个该对象的迭代器.

    Iterators

    迭代器是表示数据流的对象.重复调用迭代器的__next__()方法或将迭代器传给BIF(built-in function)next(),会返回流中的连续项,当没有可访问的数据会抛出StopIteration的异常.
    迭代器也需要有__iter__()方法,该方法返回迭代器对象本身,因此每个迭代器是可迭代的,并且可以在大多数接受其它迭代的地方使用.

    BIF iter():该函数返回一个定义了一次访问容器中一个元素的__next__()方法的迭代器.
    BIF next():通过调用迭代器(传给next的参数)的__next__()方法取回下一个元素.

    Generators

    生成器是用于创建迭代器的简单而强大的工具,是一个返回生成器迭代器的函数.它和普通函数不同在于返回值时使用yield表达式,在for-loop中可以用来产生一系列值.
    术语生成器通常指生成器函数,但是某些上下文中可能也指生成器迭代器.上面也提到了生成器迭代器,什么是生成器迭代器?
    被一个生成器函数创建的对象就叫生成器迭代器.
    本质上生成器是函数,生成器迭代器是对象.

    说这么多不如栗子来得贴切.

    栗子

    >>> s = 'abc'
    >>> it = iter(s)
    >>> it
    <iterator object at 0x00A1DB50>
    >>> next(it)
    'a'
    >>> next(it)
    'b'
    >>> next(it)
    'c'
    >>> next(it)
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
        next(it)
    StopIteration
    

    s是可迭代对象str,it是迭代器,用BIF next()可以让it移动,最终抛出异常.


    了解了迭代器的机制,可以自己添加迭代器行为到类里面:

    class Reverse:
        """Iterator for looping over a sequence backwards."""
        def __init__(self, data):
            self.data = data
            self.index = len(data)
    
        def __iter__(self):
            return self
    
        def __next__(self):
            if self.index == 0:
                raise StopIteration
            self.index = self.index - 1
            return self.data[self.index]
    

    output:

    >>> rev = Reverse('spam')
    >>> iter(rev)
    <__main__.Reverse object at 0x00A1DB50>
    >>> for char in rev:
    ...     print(char)
    ...
    m
    a
    p
    s
    

    这个类用于将串翻转输出,一次输出一个字符.它定义了一个__iter__()方法,返回一个有__next__()方法的对象,这里就是它本身.
    这个类有__iter__(),所以rev是可迭代对象,iter()直接返回self.上面不是说一次可以返回一个成员(元素)的对象才是可迭代对象吗?它怎么实现的?
    rev有__next__()方法,所以他是迭代器对象,它就可以实现一次返回一个值.为什么要这样实现,而不用__iter__()直接一次返回一个值?
    因为rev不仅是可迭代对象,它还是迭代器对象.

    If the class defines next(), then iter() can just return self
    **The iterator objects themselves are required to support the following two methods, which together form the iterator protocol:

    iterator.iter()
    Return the iterator object itself. This is required to allow both containers and iterators to be used with the for and in statements. This method corresponds to the tp_iter slot of the type structure for Python objects in the Python/C API.

    iterator.next()
    Return the next item from the container. If there are no further items, raise the StopIteration exception. This method corresponds to the tp_iternext slot of the type structure for Python objects in the Python/C API.**

    以上可以看出,这是迭代器协议规定的.这也说明了迭代器对象一定是可迭代的,但是可迭代对象不一定是迭代器对象.

    迭代器是表示数据流的对象,它可以直接给for-loop或者next()使用,但是可迭代对象要给iter(),然后才能返回一个迭代器对象.(待添加例子)


    def reverse(data):
        for index in range(len(data)-1, -1, -1):
            yield data[index]
    

    output:

    >>> for char in reverse('golf'):
    ...     print(char)
    ...
    f
    l
    o
    g
    

    这里reverse()是一个生成器函数,实现上栗相同的功能.reverse('golf')就是一个生成器迭代器对象.所以可以直接给for-loop使用


    这些概念容易混淆,可能是由于中文字符的主观原因,什么什么器的.
    再强调一下,可迭代对象(iterables),迭代器(iterators)都是对象,而生成器(generators)通常说的是生成器函数,但是也有上下文是生成器迭代器对象.


    REF:

    https://docs.python.org/3/reference/datamodel.html?highlight=container
    https://docs.python.org/3/tutorial/classes.html#iterators
    https://docs.python.org/3/library/stdtypes.html#iterator-types
    https://docs.python.org/3/glossary.html#term-iterable
    https://docs.python.org/3/glossary.html#term-generator
    https://nvie.com/posts/iterators-vs-generators/

  • 相关阅读:
    孙权用人之道:“六力”兼备
    JDK 自带工具试用(一)
    Apache ab 测试工具使用(一)
    Amoeba详细介绍
    TCP/IP 标志位 SYN ACK RST UTG PSH FIN
    ERROR 1044 (42000): Access denied for user ''@'localhost' to database 'mysql'
    jsp 中声明方法的使用
    Java遍历一个文件夹下的全部文件
    WAMP 2.5 &quot;FORBIDDEN&quot; error
    LeetCode总结--二分查找篇
  • 原文地址:https://www.cnblogs.com/katachi/p/10004672.html
Copyright © 2011-2022 走看看