python standard library iterator and generator

python 标准库 类型: 迭代器 和 生成器

每日英语:

miracle n

[英] [ˈmɪrəkl] [美] [ ˈmɪrəkəl ]

奇迹,圣迹,神迹; 令人惊奇的人(或事)

推荐一个老电影:

每个人终将都会踏上自己的绿色旅程,善恶就在一念之间。愿世界美好,温情以待。

先看一张图:

1,迭代器协议:对象需要提供next()方法,它要么返回迭代中的下一项,要么就引起一个StopIteration异常,以终止迭代。

2,可迭代对象:实现了迭代器协议对象。list、tuple、dict都是Iterable(可迭代对象),但不是Iterator(迭代器对象)。但可以使用内建函数iter(),把这些都变成Iterable(可迭代器对象)。

3,for item in Iterable 循环的本质就是先通过iter()函数获取可迭代对象Iterable的迭代器,然后对获取到的迭代器不断调用next()方法来获取下一个值并将其赋值给item,当遇到StopIteration的异常后循环结束

迭代器类型

Python 支持在容器中进行迭代的概念。 这是通过使用两个单独方法来实现的;它们被用于允许用户自定义类对迭代的支持。 将在下文中详细描述的序列总是支持迭代方法。

容器对象要提供迭代支持,必须定义一个方法:

  • container.__iter__()

    返回一个迭代器对象。 该对象需要支持下文所述的迭代器协议。 如果容器支持不同的迭代类型,则可以提供额外的方法来专门地请求不同迭代类型的迭代器。 (支持多种迭代形式的对象的例子有同时支持广度优先和深度优先遍历的树结构。) 此方法对应于 Python/C API 中 Python 对象类型结构体的 tp_iter 槽位。

迭代器对象自身需要支持以下两个方法,它们共同组成了 迭代器协议:

  • iterator.__iter__()

    返回迭代器对象本身。 这是同时允许容器和迭代器配合 forin 语句使用所必须的。 此方法对应于 Python/C API 中 Python 对象类型结构体的 tp_iter 槽位。

  • iterator.__next__()

    从容器中返回下一项。 如果已经没有项可返回,则会引发 StopIteration 异常。 此方法对应于 Python/C API 中 Python 对象类型结构体的 tp_iternext 槽位。

Python 定义了几种迭代器对象以支持对一般和特定序列类型、字典和其他更特别的形式进行迭代。 除了迭代器协议的实现,特定类型的其他性质对迭代操作来说都不重要。

一旦迭代器的 __next__() 方法引发了 StopIteration,它必须一直对后续调用引发同样的异常。 不遵循此行为特性的实现将无法正常使用。

迭代器使用实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 随便定义一个list
listArray=[1,2,3]
# 使用iter()函数
iterName=iter(listArray)
print(iterName)
# 结果如下:是一个列表list的迭代器
# <list_iterator object at 0x0000017B0D984278>

print(next(iterName))
print(next(iterName))
print(next(iterName))
print(next(iterName))#没有迭代到下一个元素,直接抛出异常
# 1
# 2
# 3
# Traceback (most recent call last):
# File "python_iterator.py", line 32, in <module>
# StopIteration

自定义迭代器实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class Fib(object):
def __init__(self, max):
super(Fib, self).__init__()
self.max = max

def __iter__(self):
self.a = 0
self.b = 1
return self

def __next__(self):
fib = self.a
if fib > self.max:
raise StopIteration
self.a, self.b = self.b, self.a + self.b
return fib

# 定义一个main函数,循环遍历每一个菲波那切数
def main():
# 20以内的数
fib = Fib(20)
for i in fib:
print(i)

# 测试
if __name__ == '__main__':
main()

生成器类型

Python 的 generator 提供了一种实现迭代器协议的便捷方式。 如果容器对象 __iter__() 方法被实现为一个生成器,它将自动返回一个迭代器对象(从技术上说是一个生成器对象),该对象提供 __iter__()__next__() 方法。 有关生成器的更多信息可以参阅 yield 表达式的文档

生成器函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 菲波那切数列
def Fib(max):
n, a, b = 0, 0, 1
while n < max:
yield b
a, b = b, a + b
n = n + 1
return '亲!没有数据了...'
# 调用方法,生成出10个数来
f=Fib(10)
# 使用一个循环捕获最后return 返回的值,保存在异常StopIteration的value中
while True:
try:
x=next(f)
print("f:",x)
except StopIteration as e:
print("生成器最后的返回值是:",e.value)
break

生成器表达式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# 一个列表
xiaoke=[2,3,4,5]
# 生成器generator,类似于list,但是是把[]改为()
gen=(a for a in xiaoke)
for i in gen:
print(i)
#结果是:
2
3
4
5

# 为什么要使用生成器?因为效率。
# 使用生成器表达式取代列表推导式可以同时节省 cpu 和 内存(RAM)。
# 如果你构造一个列表(list)的目的仅仅是传递给别的函数,
# 比如 传递给tuple()或者set(), 那就用生成器表达式替代吧!

# 本案例是直接把列表转化为元组
kk=tuple(a for a in xiaoke)
print(kk)
#结果是:
(2, 3, 4, 5)

# python内置的一些函数,可以识别这是生成器表达式,外面有一对小括号,就是生成器
result1=sum(a for a in range(3))
print(result1)
# 列表推导式
result2=sum([a for a in range(3)])
print(result2)

yield关键字

使用yield关键字实现生成器函数

1
2
3
4
5
def fib(max):  
a, b = 1, 1
while a < max:
yield a #这时a,b值分别为1,1,当然,程序也在执行到这时,返回
a, b = b, a+b

使用yield关键字实现自定义生成器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Fib:  
def __init__(self, max):
self.max = max
def __iter__(self):
self.a = 0
self.b = 1
return self
def next(self):
fib = self.a
if fib > self.max:
raise StopIteration
self.a, self.b = self.b, self.a + self.b
return fib

if __name__ == '__main__':

for f in Fib(6):
print f
坚持原创技术分享,您的支持将鼓励我继续创作!