Iterators
Iterators
迭代器是一种常见的接口,python中常用作一种访问不同容器元素的方式 -
容器可以提供一个迭代器,以按照某种顺序访问容器内元素 -
iter(iterable):创建迭代器,接受任何可迭代的东西,返回可迭代元素的迭代器
- next(iterator):推进迭代器,返回迭代器的下一个元素 -
不同迭代器可以迭代相同值,但它们彼此之间是独立的 -
使用list,tuple或sorted函数可以查看一个迭代器的剩余元素 -
当迭代器到达末尾,Python会返回一个StopIteration的异常 -
所有迭代器都是可变对象
1
2
3
4
5
6
7
8
s = [[1,2],3,4,5]
t = iter(s)
u = iter(s)
print("t:",next(t))
print("u:",next(u))
print("t:",next(t))
list(t)
print(next(t))t: [1, 2]
u: [1, 2]
t: 3
---------------------------------------------------------------------------
StopIteration Traceback (most recent call last)
Cell In[4], line 8
6 print("t:",next(t))
7 list(t)
----> 8 print(next(t))
StopIteration:
Dictionary Itertion
字典的键,值以及键值对都是可遍历的 ,可以生成迭代器 字典中的键值对顺序取决于它们的添加顺序(Python3.6+) 迭代各项目的方法如下
1
2
3
4
5
6
7
8
9
10
11
d = {'one':1, 'two':2, 'three':3}
d['zero'] = 0
# 遍历键
k = iter(d.keys()) # iter(d)
print(next(k))
# 遍历值
v = iter(d.values())
print(next(v))
# 遍历键值对
i = iter(d.items()) # 以元组形式迭代
print(next(i))one
1
('one', 1)
注意:若在迭代器创建后,字典发生了结构上的改变(增加,减少元素等),迭代器会失效。若只是改变键对应的值则不会。
For Statement
for循环可以遍历迭代器本身,可以从迭代器当前位置遍历到迭代器末尾,但这会推进迭代器,故不能重复使用 而可迭代对象可以从头到尾遍历多次
1
2
3
4
5
6
r = range(3,6)
ri = iter(r)
for i in ri:
print(i)
for i in ri:
print(i)3
4
5
Built-in Function for Iteration
许多python内置的序列操作使用迭代器作为返回值,以惰性方式计算
惰性计算意味着只有被请求时才计算结果 e.g.
map(func, iterable):接受一个函数与一个可迭代对象,将该函数应用于可迭代对象中的每一个元素,返回一个迭代器遍历可迭代对象中所有x在func下的值
filter(func, iterable):接受一个断言函数与一个可迭代对象,返回一个迭代器遍历可迭代对象中所有在func下为真的x
zip(first_iter, second_iter):接受两个可迭代对象,返回迭代器遍历相同索引的(x,y)对
reversed(sequence):接受一个序列,返回迭代器反向遍历该序列
1
2
3
4
5
bcd = ['b', 'c', 'd']
m = map(lambda x: x.upper(), bcd) # 返回一个迭代器
print(next(m))
print(next(m))
print(next(m))B
C
D
1
2
3
4
5
6
7
def double(x):
print(x, '=>',2*x)
return 2*x
m = map(double, range(3,7))
f = lambda y: y>=10
t = filter(f,m) # 仅遍历满足f函数下的返回值
list(filter(f,m)) # 将所有可能的返回值存入列表3 => 6
4 => 8
5 => 10
6 => 12
[10, 12]
Zip
zip函数返回迭代器,遍历相同索引的值组成的元组 若一个可迭代对象比另一个长,zip会跳过多余的 zip可以接受多个可迭代对象
1
2
3
4
5
print(list(zip([1,2],[3,4])))
print(list(zip([1,2],[3,4,5])))
print(list(zip([1,2],[3,4,5], [6,7])))[(1, 3), (2, 4)]
[(1, 3), (2, 4)]
[(1, 3, 6), (2, 4, 7)]
e.g. 检测任意一个序列是否为回文序列,使用zip
1
2
3
4
5
6
7
8
9
10
11
def palindrome(s):
# >>> palindrome([3,1,4,1,5])
# False
# >>> palindrome([3,1,4,1,3])
# True
# >>> palindrome('seveneves')
# True
return all([a==b for a,b in zip(s,reversed(s))])
if __name__ == '__main__':
print(palindrome([3,1,4,1,3]))
print(palindrome('seveneves'))True
True
Using Iterators
使用迭代器的代码对数据本身更改不大 - 当数据表示形式改变时,使用迭代器可以不必重写代码 - 其他人更可能在他们的数据上使用你的代码 迭代器将序列中的元素与所在位置绑定 - 将对象传递给其他函数时始终保留着位置 - 可以确保序列中的每个元素只执行一次 - 传递迭代器限制了对序列执行的操作,即只能请求下一个值