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/

posted @ 2018-11-22 23:26  katachi  阅读(312)  评论(0编辑  收藏  举报