深入理解python迭代
作者: Trey Hunner
1本文内容说明
2本文的python运行环境说明
一、什么是迭代
(斜体字内容来自百度百科)迭代,就是重复反馈的活动,目的通常是为了逼近所需的目标,每一次重复成为一次迭代。每一次迭代的结果都会作为下一次的初始值。
对计算机特定程序中需要反复执行的子程序,进行一次重复,即重复执行程序中的循环,直到满足某种条件为止,亦称为迭代。
我的理解:python中的迭代,按上面的定义,需要反复执行的子程序就是next(),满足的条件就是StopIteration这个TypeError产生。
二、python中的for循环
python中,没有用索引形成的for循环,例如:
for (i = 0, i < = 10, i++)
python中的循环,是for each in形式的循环:
for number in numbers:
三、可迭代和序列
- python中的序列,包括列表(list)、元组(tuple)和字符串(string);
- 迭代意味着循环,可迭代意味着可循环可遍历,反之,可循环可遍历意味着可迭代;
- 所有python中的序列,都是可遍历的,也就是可迭代的;
- python中,除了序列外,字典、集合、文件以及生成器,都是可迭代的。
四、迭代器
“迭代器”就是可以驱动“可迭代对象”的“东西”。python中,可以使用iter()函数获取“”可迭代对象的“迭代器”
一旦获得“迭代器”,就可以将它传递给内置的next()函数,获取它的下一项。
"""首先定义一个numbers列表,然后通过生成器表达式
生成一个生成器对象squares"""
>>> numbers = [1, 2, 3. 4. 5]
>>> squares = (number ** 2 for number in numbers)
#my_iter是生成器squares的迭代器
#由iter函数生成
>>> my_iter = iter(squares)
>>> my_iter
>>> <list_iterator object at 0x10a9ba208>
#next函数返回迭代器my_iter的下一项
>>> next(my_iter)
1
>>> next(my_iter)
4
>>> next(my_iter)
9
>>>
迭代器是有“状态的”,一旦消耗了一项,它就会“消失”,也就是说,每调用一次迭代器,就消耗一个迭代器,直到产生一个StopIteration异常
>>> next(my_iter)
16
>>> next(my_iter)
25
>>> next(my_iter)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
>>>
再看下面这个例子:
>>> numbers = [1, 2, 3, 4, 5]
>>> squares = (number ** 2 for number in numbers)
>>> next(squares)
1
>>> next(squares)
4
>>> for number in squares:
... print(number)
...
9
16
25
>>>
为什么结果是这样?for循环只输出了9、16和25?
因为在第3行和第5行,两次next函数调用,使得squares的迭代器(因为squares是生成器,而生成器本身也是迭代器)“消失了”2个,只剩下了后面的3个。
结合上面对“可迭代对象”及“迭代器”的讨论,可以对python的for循环作如下理解:
Created with Raphaël 2.2.0 开始 从给定的可迭代对象获得迭代器 反复从迭代器中获取下一项 是否得到一个StopIteration异常? 结束 yes no
下面这段代码“定义”了python的for:
def funky_loop(iterable, action_todo):
iterator = iter(iterable)
done_looping = False
while not done_looping:
try:
item = next(iterator)
except StopIteration:
done_looping = True
else:
action_todo(item)
五、迭代器协议
迭代器协议(Iterator Protocol),定义了iter和next如何工作,python中所有形式的迭代都是由迭代器协议驱动的。
“生成器”本身就是迭代器(可以用next获取下一项),也可以用for循环遍历,这就引出一个概念:迭代器是可迭代的,当我们在迭代器上使用iter时,iter返回迭代器自己,但迭代器与可迭代对象不同的是:迭代器对象没有长度,不能被索引。
"""next()"""
>>> numbers = [1, 2, 3, 4, 5]
>>> squares = (number **2 for number in numbers)
>>> next(squares)
1
>>> next(squares)
4
>>> next(squares)
9
"""for"""
>>> numbers = [1, 2, 3, 4, 5]
>>> squares = (number **2 for number in numbers)
>>> for square in squares:
... print(square)
...
1
4
9
16
25
>>>
"""len"""
>>> len(squares)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: object of type 'generator' has no len()
>>> my_iter = iter(squares)
>>> len(my_iter)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: object of type 'generator' has no len()
>>>
对象 | 可迭代 | 迭代器 |
可迭代对象 | 是 | 不一定 |
迭代器 | 是 | 是 |
生成器 | 是 | 是 |
列表 | 是 | 否 |
python迭代器协议总结
- 可迭代对象传给iter函数,获得迭代器;
- 迭代器:
- 可传递给next函数,它将给出下一项,如果没有下一项,给出StopIteration异常;
- 可传递给iter函数,返回自身的一个迭代器
- 这些语句反过来也是正确的:
- 任何可以在不引发TypeError异常的情况下传递给iter的东西都是可迭代的;
- 任何可以在不引发TypeError异常的情况下传递给next的东西都是一个迭代器
- 当传递给iter时,任何返回自身的东西都是一个迭代器