一文读懂python迭代器与生成器の拾遗

时间:2020-8-24 作者:admin


Iterators and Generators

一文读懂python迭代器与生成器の拾遗

1、迭代器 Iterators

何谓可迭代对象,何谓迭代器,它们之间关系如何?先谈谈这几个概念

  • 可迭代对象(Iterables)
    • 可迭代对象可以是任何对象,不一定是可以返回迭代器的数据结构,其主要目的是返回其所有元素
    • 可迭代可表示有限和无限的数据源
    • 一个可迭代的对象将直接或间接定义两个方法:
      • __iter __()方法,该方法必须返回迭代器对象
      • 而 __next()__方法,则借助它调用的迭代器
  • 迭代器(Iterators)
    • python中的Iterator是一个对象,用于迭代列表,元组,字典和集合之类的可迭代对象
    • 使用 iter() 方法初始化 Iterator 对象。 它使用 next()方法进行迭代
    • __iter(iterable)__ 方法 用于初始化迭代器,返回一个迭代器对象
    • next ( __next__ in Python 3)方法, next() 返回可迭代对象的下一个值,当我们使用for循环遍历任何可迭代对象时,在内部它会使用 iter() 方法获取一个迭代器对象,该对象进一步使用 next() 方法进行迭代。 此方法会在迭代结束引发 StopIteration表示迭代结束

1.1 可迭代对象(Iterables)

我们已经知道,可以直接作用于 for循环 的数据类型有以下几种:

  • 一类是集合数据类型,如 list、tuple、dict、set、str 等

  • 一类是 generator,包括 生成器 和 带 yield 的 generator function

  • 这些可以直接作用于for循环的对象统称为可迭代对象:Iterable

  • 可以使用isinstance()判断一个对象是否是Iterable对象

如下,常见的数据类型列表、字典、元组、集合、字符串都是可迭代的对象,但整数 666 不可迭代

In [90]: from collections.abc import Iterable

In [91]: isinstance([],Iterable)
Out[91]: True

In [92]: isinstance({},Iterable)
Out[92]: True

In [93]: isinstance('eva',Iterable)
Out[93]: True

In [94]: isinstance((1,),Iterable)
Out[94]: True

In [95]: isinstance(666,Iterable)
Out[95]: False

In [96]: isinstance({3},Iterable)
Out[96]: True

In [97]: isinstance({'a':1},Iterable)
Out[97]: True

1.2 迭代器(Iterators)

  • 迭代器(节省内存)
  • 生成器都是 Iterator 对象,但 list、dict、str 虽然是 Iterable,却不是 Iterator
  • 把 list、dict、str 等 Iterable 变成 Iterator 可以使用 iter() 函数:

迭代器遵守迭代器协议,迭代器协议定义如下:

A Python iterator object must implement two special methods, __iter__() and __next__(), collectively called the iterator protocol.

Python迭代器对象必须实现__iter __()和__next __()这两个特殊方法,统称为迭代器协议。

通过 dir(obj) 或 obj.__dir__() 方法来查看 该对象的属性方法

  • 可迭代对象 只有 __iter__() 属性方法
In [106]: x = [1,2,3]

In [107]: y = iter(x)

In [108]: dir(x)                    # dir(obj) is same as obj.__dir__()
Out[108]:
['__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']

In [109]:
  • 迭代器 必须 同时 具有 __iter__() 和 __next__() 方法
In [109]: y.__dir__()         # dir(obj) is same as obj.__dir__()
Out[109]:
['__getattribute__',
 '__iter__',
 '__next__',
 '__length_hint__',
 '__reduce__',
 '__setstate__',
 '__doc__',
 '__repr__',
 '__hash__',
 '__str__',
 '__setattr__',
 '__delattr__',
 '__lt__',
 '__le__',
 '__eq__',
 '__ne__',
 '__gt__',
 '__ge__',
 '__init__',
 '__new__',
 '__reduce_ex__',
 '__subclasshook__',
 '__init_subclass__',
 '__format__',
 '__sizeof__',
 '__dir__',
 '__class__']

In [110]:

通过迭代器进行迭代
使用 next() 函数手动遍历迭代器的所有项目。当我们到达末尾并且没有更多数据要返回时,它将引发StopIteration Exception。示例如下:
注意:next(obj) is same as obj.__next__()

# define a list
my_list = [4, 7, 0, 3]

# get an iterator using iter()
my_iter = iter(my_list)

# iterate through it using next()

# Output: 4
print(next(my_iter))

# Output: 7
print(next(my_iter))

# next(obj) is same as obj.__next__()

# Output: 0
print(my_iter.__next__())

# Output: 3
print(my_iter.__next__())

# This will raise error, no items left
next(my_iter)

输出:

4
7
0
3
Traceback (most recent call last):
  File "<string>", line 24, in <module>
    next(my_iter)
StopIteration

再如下所示,x 是可迭代的,而 y 是迭代器单独的一个实例,y 可以迭代 x 产生值,在迭代结束引发 StopIteration表示迭代结束

In [98]: x = [1, 2, 3]

In [99]: y = iter(x)

In [100]: next(y)
Out[100]: 1

In [101]: next(y)
Out[101]: 2

In [102]: next(y)
Out[102]: 3

In [103]: next(y)
---------------------------------------------------------------------------
StopIteration                             Traceback (most recent call last)
<ipython-input-103-81b9d2f0f16a> in <module>
----> 1 next(y)

StopIteration:

In [104]: type(x)
Out[104]: list

In [105]: type(y)
Out[105]: list_iterator

In [106]:   

coding 实际中,列表写 for 列表 遍历,一般如下:

x = [1, 2, 3]
for elem in x:
    ...

其实际过程是这样的

# create an iterator object from that iterable
iter_obj = iter(iterable)

# infinite loop
while True:
    try:
        # get the next item
        element = next(iter_obj)
        # do something with element
    except StopIteration:
        # if StopIteration is raised, break from loop
        break

一文读懂python迭代器与生成器の拾遗

  • list 这个可迭代的类型 通过 iter() -转换–> 迭代器
  • 其中 for 循环语法 替我们 完成了 __iter__() 这个转化过程
  • 通过迭代器的 next() 方法 来完成 for 循环中取值这个步骤

1.3 迭代器作用于for循环 Working of for loop for Iterators

iterable_value = 'iterables'                  # 可迭代的字符串
iterable_obj = iter(iterable_value)           # 初始化迭代器

while True:
    try:
        # Iterate by calling next
        item = next(iterable_obj)
        print(item)
    except StopIteration:
        # exception will happen when iteration will over
        break

输出:

i
t
e
r
a
b
l
e
s

1.4 构建自定义迭代器 Building Custom Iterators

python中从头开始构建迭代器还是很容易的,只需要实现__iter __() 和__next __() 方法即可。 __iter __() 方法返回迭代器对象本身,如果需要的话,也可以执行一些初始化操作。 __next __() 方法必须返回序列中的下一项,在到达末尾以及随后的调用中,它必须引发StopIteration

示例如下:
将在每次迭代中提供下一个2的幂,幂指数从零开始一直到用户设置的数字
注意:next(obj) is same as obj.__next__()

class PowTwo:
    """Class to implement an iterator
    of powers of two"""

    def __init__(self, max=0):
        self.max = max

    def __iter__(self):
        self.n = 0
        return self

    def __next__(self):
        if self.n <= self.max:
            result = 2 ** self.n
            self.n += 1
            return result
        else:
            raise StopIteration


# create an object
numbers = PowTwo(3)

# create an iterable from the object
i = iter(numbers)

# Using next to get to the next iterator element
print(next(i))
print(next(i))
print(i.__next__())
print(next(i))
print(i.__next__())

输出:

1
2
4
8
Traceback (most recent call last):
  File "/home/xxx/Desktop/Untitled-1.py", line 32, in <module>
    print(next(i))
  File "<string>", line 18, in __next__
    raise StopIteration
StopIteration

同样可以使用for循环来迭代 这个迭代器类


>>> for i in PowTwo(5):
...     print(i)
...     
1
2
4
8
16
32

1.5 Python无限迭代器 Python Infinite Iterators

不必耗尽迭代器对象中的项目,可以有无限迭代器(永无止境)。处理此类迭代器时,我们必须小心。下边演示一个无限迭代器的简单示例:
可以使用两个参数调用内置函数iter()函数,其中第一个参数必须是可调用对象(函数),第二个参数是前哨,迭代器将调用此函数,直到返回的值等于哨兵。

It is not necessary that the item in an iterator object has to be exhausted. There can be infinite iterators (which never ends). We must be careful when handling such iterators.
Here is a simple example to demonstrate infinite iterators.

The built-in function iter() function can be called with two arguments where the first argument must be a callable object (function) and second is the sentinel. The iterator calls this function until the returned value is equal to the sentinel.

>>> int()
0
>>> int()
0
>>> int()
0

>>> inf = iter(int,1)
>>> next(inf)
0
>>> next(inf)
0

我们可以看到 int() 函数始终返回0。因此,将其作为 iter(int,1)传递将返回一个迭代器,该迭代器调用 int() 直到返回值等于1。然鹅这永远不会发生,并且我们得到一个无限迭代器。
We can see that the int() function always returns 0. So passing it as iter(int,1) will return an iterator that calls int() until the returned value equals 1. This never happens and we get an infinite iterator.

我们还可以构建自己的无限迭代器。 理论上,以下迭代器将返回所有奇数。
We can also build our own infinite iterators. The following iterator will, theoretically, return all the odd numbers.

class InfIter:
    """Infinite iterator to return all
        odd numbers"""

    def __iter__(self):
        self.num = 1
        return self

    def __next__(self):
        num = self.num
        self.num += 2
        return num

运行结果举例如下:

>>> a = iter(InfIter())
>>> next(a)
1
>>> next(a)
3
>>> next(a)
5
>>> next(a)
7

依此类推…
And so on…

在迭代这些类型的无限迭代器时,请小心包含终止条件。
Be careful to include a terminating condition, when iterating over these types of infinite iterators.

使用迭代器的优点是节省了资源。 如上所示,我们无需将整个数字系统存储在内存中就可以获得所有奇数。 从理论上讲,我们可以在有限内存中包含无限项。
The advantage of using iterators is that they save resources. Like shown above, we could get all the odd numbers without storing the entire number system in memory. We can have infinite items (theoretically) in finite memory.

2、生成器 Generators

一文读懂python迭代器与生成器の拾遗

声明:本文内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎进行举报,并提供相关证据,工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。