迭代器
迭代器是拥有一个next()方法的对象。当你需要获取一个对象的下一项时,可以通过调用迭代器的next()方法获得它,当所有的条目取出后,就会引发一个StopIteration异常来说明迭代结束。
我们可以使用迭代器不但可以访问序列对象,也可以访问类序列对象(例如一个字典的键或值、一个文件的行)
迭代器的创建
对一个对象调用iter()方法来获取它的迭代器。
iter(obj)
传递一个参数给iter(),首先,它会检测这个参数是否为序列,如果是,它就会根据索引一直迭代到序列结束。
iter(func, sentinel)
如果使用这种方法,我们需要传递两个参数,它会反复地调用func,直到迭代器的某一值等于sentinel。
不可变对象的迭代
一个序列的迭代器只是记录你当前到达第几个元素,如果你在迭代过程中改变了元素,更新会立即反应到你所迭代的条目上,就会引发错误。
在迭代字典的键时,是绝对不能改变这个字典的,但是使用字典的keys()方法是可以的,因为它返回一个独立于字典的列表。
for循环
for语句会自动调用迭代器的next()方法并捕获异常。
使用迭代器做for循环的代码与使用序列条目几乎一样,在大多数情况下,我们无法分辨迭代是一个序列还是迭代器。
迭代的操作
同过几个常见的迭代操作来增强对迭代的理解。
手动迭代
我们在处理某个可迭代对象中的元素,但由于某种原因不能使用for循环,可以手动使用next()方法。
>>> items = [1, 2, 3]
>>> it = iter(items)
>>> next(it)
1
>>> next(it)
2
>>> next(it)
3
>>> next(it)
Traceback (most recent call last):
File "<pyshell#5>", line 1, in <module>
next(it)
StopIteration
反向迭代
使用内建函数reversed()实现反向迭代。
>>> for item in reversed([1, 2, 3]):
print item
3
2
1
索引-值对的迭代
使用内建函数enumerate()实现索引-值对的迭代。
>>> my_list = ['Python', 'C++', 'C', 'Java', 'PHP', 'R']
>>> for index, value in enumerate(my_list):
print index, value
0 Python
1 C++
2 C
3 Java
4 PHP
5 R
迭代多个序列
如果我们想要迭代的元素在多个序列中,就需要同时迭代多个序列,使用zip()方法实现。zip()创建一个迭代器,该迭代器产生出元组(x, y),其中x取自序列a,y取自于序列b,整个迭代的长度和其中最短的序列长度相同。
>>> a = [0, 1, 2, 3]
>>> b = ['Python', 'C++', 'Java', 'PHP', 'C', 'R']
>>> for i in zip(a, b):
print i
(0, 'Python')
(1, 'C++')
(2, 'Java')
(3, 'PHP')
迭代器的作用
- 提供了可拓展的迭代器接口;
- 对列表迭代带来了性能上的增强;
- 在字典迭代中性能提升;
- 创建真正的迭代接口,而不是原来的随即对象访问;
- 与所有已经存在的用户定义的类型以及拓展的模拟序列和映射的对象向后兼容;
- 迭代非序列集合时,创建更简洁可读的代码。
生成器
生成器是列表解析的一个拓展。
生成器是一个带有yield语句的函数,允许你返回一个值,然后“暂停”代码的执行,稍后恢复。
生成器在每次计算出一个条目后,把这个条目“yield(生成)”出来,生成器表达式使用了‘延迟计算’,节省了内存。
列表解析:
[expr for iter_var in iterable if cond_expr]
生成器表达式:
(expr for iter_var in iterable if cond_expr)
函数中只要出现了yield语句就会将其转变成一个生成器,与普通函数不同的是,生成器只会在响应迭代操作时才运行。
使用生成器创建新的迭代模式:
def frange(start, stop, increment):
'create a new range() about float number.'
x = start
while x < stop:
yield x
x += increment