Python系列5——迭代对象、迭代器、生成器

目录

 

1 可迭代对象

1.1什么是可迭代对象、如何判断是否是可迭代对象

2 迭代器

3 for循环的本质

4 生成器


1 可迭代对象

1.1什么是可迭代对象、如何判断是否是可迭代对象

在Python中,我们把所有可以迭代的对象统称为可迭代对象,有一个类专门与之对应:Iterable。大多数容器也是可迭代的。但还有很多东西是可迭代的。例如打开的文件、打开的套接字等等。在容器通常是有限的情况下,可迭代可以表示无限的数据流。

可迭代对象是可以返回迭代器(目的是返回其所有元素)的任何对象,不一定是数据结构。这听起来有点尴尬,但是可迭代对象和迭代器之间存在重要区别。

>>> from collections import Iterable
>>> isinstance(123, Iterable)
False
>>> isinstance(True, Iterable)
False
>>> isinstance('abc', Iterable)
True
>>> isinstance([], Iterable)
True
>>> isinstance({}, Iterable)
True
>>> isinstance((), Iterable)
True

怎么让一个对象可迭代呢?毕竟,很多时候,我们需要用到的对象不止Python内置的这些数据类型,还有自定义的数据类型。答案就是实现__iter__()方法,只要一个对象定义了__iter__()方法,那么它就是可迭代对象。

from collections.abc import Iterable
class A():
    def __iter__(self):
        pass
print('A()是可迭代对象吗:',isinstance(A(),Iterable))

//结果输出为:
//A()是可迭代对象吗: True

只要一个对象定义了__iter__()方法,那么它就是可迭代对象。

2 迭代器

迭代器是对可迭代对象的改造升级,上面说过,一个对象定义了__iter__()方法,那么它就是可迭代对象,进一步地,如果一个对象同时实现了__iter__()和__next__()方法,那么它就是迭代器。

在Python中,也有一个类与迭代器对应:Iterator。所以,要判断一个类是否是迭代器,只要判断是否是Iterator类的实例即可。

from collections.abc import Iterable
from collections.abc import Iterator
class B():
    def __iter__(self):
        pass
    def __next__(self):
        pass
print('B()是可迭代对象吗:',isinstance(B(), Iterable))
print('B()是迭代器吗:',isinstance(B(), Iterator))

/*
结果输出如下:
B()是可迭代对象吗: True
B()是迭代器吗: True
*/

3 for循环的本质

x = [1, 2, 3]
x = iter(x)
try:
    while True:
        print(next(x))
except StopIteration:
    pass

从上我们可以看出,for循环的本质是先将可迭代对象列表x利用iter(x)调用__iter__()方法,返回迭代器。然后通过next(x)可以调用魔法函数__next__(),实现下一个元素的获取。

4 生成器

终于,我们到达了目的地!生成器是我最喜欢的Python语言特性。生成器是一种特殊的迭代器,优雅的迭代器。

生成器使您可以像上面的Fibonacci序列迭代器示例一样编写迭代器,但是使用简洁的语法,避免使用__iter __()和__next __()方法编写类。

def fib(max):
    n, a, b = 0, 0, 1
    while n < max:
        print(b)
        a, b = b, a + b
        n = n + 1
    return 'done'

>>> fib(6)
1
1
2
3
5
8
'done'

仔细观察,可以看出,fib函数实际上是定义了斐波拉契数列的推算规则,可以从第一个元素开始,推算出后续任意的元素,这种逻辑其实非常类似generator。也就是说,上面的函数和generator仅一步之遥。要把fib函数变成generator,只需要把print(b)改为yield b就可以了:

def fib(max):
    n, a, b = 0, 0, 1
    while n < max:
        yield b
        a, b = b, a + b
        n = n + 1
    return 'done'

这里,最难理解的就是generator和函数的执行流程不一样。函数是顺序执行,遇到return语句或者最后一行函数语句就返回。而变成generator的函数,在每次调用next()的时候执行,遇到yield语句返回,再次执行时从上次返回的yield语句处继续执行。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章