- 跳过可迭代对象的开始部分
- 问题:
- 想遍历一个可迭代对象,但是它开始的某些元素并不感兴趣,想跳过它们。
- 解决方案:
- itertools 模块中有一些函数可以完成这个任务。itertools.dropwhile()函数接收一个函数对象和一个可迭代 对象,丢弃原有序列中直到函数返回 True 之前的所有元素(说的真绕。。。),然后返回后面所有的元素。
- 假定读取一个开始部分是几行注释的文件:
with open("password.txt") as f:
for line in f:
print(line, end= "")
"""
##
# User Database
#
# Note that this file is consulted directly only when the system is running
# in single-user mode. At other times, this information is provided by
# Open Directory.
#
##
nobody:*:-2:-2:Unprivileged User:/var/empty:/usr/bin/false
root:*:0:0:System Administrator:/var/root:/bin/sh
"""
- 如果像跳过开始部分的注释行的话,可以这么做:
from itertools import dropwhile
with open("password.txt") as f:
for line in dropwhile(lambda line: line.startswith("#"),f):
print(line, end= "")
"""
nobody:*:-2:-2:Unprivileged User:/var/empty:/usr/bin/false
root:*:0:0:System Administrator:/var/root:/bin/sh
"""
- 这个例子是基于某个测试函数跳过开始的元素。如果已经明确直到了要跳过的元素的个数的话,可以使用 itertools.islice() 来代替。比如:
from itertools import islice
items = ["a", "b", "c", 1, 4, 10, 15]
for x in islice(items, 3, None):
print(x, end= " ") # 1 4 10 15
for x in islice(items, None, 3):
print(x, end= " ") # a, b, c
-
在这个例子中, islice()函数最后那个 None 参数指定了需要获取从第三个元素到最后的所有元素,如果None和3的 位置对调,就是仅仅提取前三个元素。和切片操作原理一样。
-
讨论: 函数dropwhile()和islice()其实就是两个“帮助函数”(我很想知道老外的语境。。。),为的就是避免写 下面这种冗余代码:
with open("password.txt") as f:
while True:
line = next(f, "")
if not line.startswith("#"):
break
while line:
print(line, end= "")
line = next(f, None)
- 跳过一个可迭代对象的开始部分跟通常的过滤是不同的。比如,上述代码的第一部分可能回这样重写:
with open("password.txt") as f:
lines = (line for line in f if not line.startswith("#"))
for line in lines:
print(line, end= "")
- 这样写的话,确实可以跳过开始部分的注释行,但是同样也跳过文件中其他所有的注释行。
- 本节的案例使用所有可迭代对象,包括事先不能确定大小的,比如迭代器,文件及类似对象。