基本概念
迭代器协议: 对象需要提供next方法,它要么返回迭代中的下一项,要么就引起一个StopIteration异常,以终止迭代。
可迭代对象: 实现了迭代器协议的对象。
协议: 是一种约定, 可迭代对象实现了迭代器协议, python的内置工具for,in成员关系测试, map函数等使用迭代器协议访问可迭代对象。
文件迭代器
>>> f = open('./test.py', 'r')
>>> f.readline()
"s1 = 'spam'\n"
>>> f.readline()
"s2 = 'scam'\n"
>>> f.readline()
'res = []\n'
>>> f.readline()
'print(res)\n'
>>> f.readline()
''
>>> f.readline()
''
>>>我们可以通过readline读取文件内容的下一行, 直到到达文件末尾返回一个空字符串。
其实, 文件对象还有一个_next_方法, 也是读取文件下一个内容, 不过当到达文件末尾时候, __next__会触发StopIteration异常。
>>> f = open('./test.py', 'r')
>>> f.__next__()
"s1 = 'spam'\n"
>>> f.__next__()
"s2 = 'scam'\n"
>>> f.__next__()
'res = []\n'
>>> f.__next__()
'print(res)\n'
>>> f.__next__()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
>>>这其实指的就是python中的可迭代协议: 有__next__方法的对象会前进到下一个结果, 等到了末尾时候会触发StopIteration。 任何上述这类对象都是可迭代的。
这类对象可以使用for循环或者其他迭代工具进行遍历, 因为所有迭代工具内部都是每次调用__next__, 并捕捉StopIteration异常。
# for循环逐行读取 代码简单, 运行速度快, 内存使用合理
>>> for line in open('./test.py', 'r'): print(line, end=' ')
...
s1 = 'spam'
s2 = 'scam'
res = []
print(res)
>>>或者使用readlines方法, 但是不推荐, 性能不好。
>>> for line in open('./test.py', 'r').readlines(): print(line, end=' ')
...
s1 = 'spam'
s2 = 'scam'
res = []
print(res)
>>>当然也支持使用while循环
f = open('./test.py', 'r')
while True:
line = f.readline()
if not line: break
print(line, end=' ')手动迭代: iter, next
python3提供了一个内置函数next(), 它会自动调用_next_方法, 给定一个迭代对象x,调用next(x)等同于x.__next__()。
>>> f = open('./test.py', 'r')
>>> next(f)
"s1 = 'spam'\n"
>>> next(f)
"s2 = 'scam'\n"
>>> next(f)
'res = []\n'
>>> next(f)
'print(res)\n'
>>> next(f)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
>>>iter内置函数会从可迭代对象中获得一个迭代器,该迭代对象含有next()。
>>> L = [1, 2, 3]
>>> L.next()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'list' object has no attribute 'next'
>>> next(L)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'list' object is not an iterator
>>> I = iter(L)
>>> next(I)
1
>>> next(I)
2
>>> next(I)
3
>>> next(I)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
>>>其他内置类型迭代器
# 遍历字典
>>> D = {'name': 'kobe', 'age': 20}
>>> for x in D.keys(): print(x, '=>', D[x])
...
name => kobe
age => 20
>>>其实字典也有一个迭代器
>>> D
{'name': 'kobe', 'age': 20}
>>> I = iter(D)
>>> next(I)
'name'
>>> next(I)
'age'
>>> next(I)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
>>>或者直接使用for循环。
>>> for key in D: print(key, '=>', D[key])
...
name => kobe
age => 20
>>>列表解析
# 一个基本的列表解析
>>> L = [x + 10 for x in range(10)]
>>> L
[10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
>>>列表解析运行速度快于for循环, 这是因为它们的迭代在解释器内部是以C语言速度执行的。
当我们考虑在一个序列中对每一项执行一个操作时候,我们其实就可以考虑使用列表解析。