---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-37-fd8bddd1ee1f> in <module>()
----> 1 next(P)
TypeError: '_wrap_close' object is not an iterator
在 Python 3.X 中,popen 支持 P.__next__() 方法,但不支持 next(P) 内置函数。由于后者定义来调用前者,这似乎不正常,但是如果用 for 循环或者其他的迭代环境来自动迭代这些对象,都能正确工作。使用顶级 iter 调用也可以。
1 2
I = iter(P) next(I)
' 卷的序列号是 C8D4-BF33\n'
1
I.__next__()
'\n'
迭代协议也是我们必须把某些结果包装到一个 list 调用中以一次性看到它们的值的原因。可迭代对象一次返回一个结果,而不是一个实际的列表:
1 2
R = range(5) R
range(0, 5)
1 2
I = iter(R) next(I)
0
1
next(I)
1
1
list(range(5))
[0, 1, 2, 3, 4]
2. 列表解析
列表解析是最常应用迭代协议的环境之一。在遍历一个列表的时候,可以使用 range 来修改它:
1 2 3 4
L = [1, 2, 3, 4, 5] for i inrange(len(L)): L[i] += 10 L
[11, 12, 13, 14, 15]
这可能不是 Python 中的最佳实践。我们可以使用列表解析表达式来替代该循环:
1 2
L = [x + 10for x in L] L
[21, 22, 23, 24, 25]
列表解析并不完全和 for 循环语句版本相同,因为它产生一个新的列表对象(如果有对最初的列表的多个引用,可能会有关系)。
2.1 列表解析基础知识
从语法上讲,列表解析的语法源自于集合理论表示法中的一个结构,该结构对集合中的每个元素应用一个操作。列表解析看上去就像是一个反向的 for 循环。
列表解析写在一个方括号中,因为它们最终是构建一个新的列表的方式。它们以一个任意的表达式开始,该表达式使用我们所组成的一个循环变量(x + 10)。后面跟着看做是一个 for 循环头部的部分,它声明了循环变量,以及一个可迭代对象(for x in L)。
列表解析并非真的是必需的,我们总是可以用一个 for 循环手动地构建一个表达式结果的列表。但是列表解析编写起来更加精简,并且由于构建结果列表的这种代码样式在 Python 代码中十分常见,因此可以将它们用于多种环境。
此外,列表解析比手动的 for 循环语句运行的更快,因为它们的迭代在解释器内部是以 C 语言的速度执行的。
2.2 在文件上使用列表解析
当我们开始考虑在一个序列中的每项上执行一个操作时,都可以考虑使用列表解析。
1 2
lines = [line.rstrip() for line inopen('log.txt')] lines
range 对象支持 len 和索引,它不是自己的迭代器(手动迭代时,使用 iter 产生一个迭代器),并且,它支持在其结果上的多个迭代器,这些迭代器会记住它们各自的位置:
1 2
R = range(3) # range 支持多个迭代器 next(R)
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-22-34d331752715> in <module>()
1 R = range(3) # range 支持多个迭代器
----> 2 next(R)
TypeError: 'range' object is not an iterator
1
I1 = iter(R)
1
next(I1)
0
1
next(I1)
1
1
I2 = iter(R) # 一个 range 上有两个迭代器
1
next(I2)
0
1
next(I1) # I1 和 I2 的位置不同
2
zip、map 和 filter 不支持相同结果上的多个活跃迭代器:
1 2 3 4
Z = zip((1, 2, 3), (10, 11, 12)) I1 = iter(Z) I2 = iter(Z) # 一个 zip 上的两个迭代器 next(I1)
(1, 10)
1
next(I1)
(2, 11)
1
next(I2) # I2 和 I1 在同一位置
(3, 12)
使用类来编写自己的可迭代对象的时候,将会看到通常通过针对 iter 调用返回一个新的对象,来支持多个迭代器;单个迭代器一般意味着一个对象返回其自身。生成器函数和表达式的行为就像 map 一样支持单个的活跃迭代器。
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-42-02c2ef8731e9> in <module>()
----> 1 next(K)
TypeError: 'dict_keys' object is not an iterator
1 2
I = iter(K) # 可迭代的视图有一个迭代器 next(I) # 可以手动使用,但不支持 len 和索引
'a'
1
next(I)
'b'
1
for k in D.keys(): print(k, end=' ')
a b c
和所有的迭代器一样,我们总可以通过把一个 Python 3.X 字典视图传递到 list 内置函数中,从而强制构建一个真正的列表:
1 2
K = D.keys() list(K)
['a', 'b', 'c']
1
K[0]
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-48-abefddd6f6bf> in <module>()
----> 1 K[0]
TypeError: 'dict_keys' object does not support indexing