4.8 跳过�迭代对象的开始部分¶

问题¶

你想�历一个�迭代对象,但是它开始的�些元素你并�感兴趣,想跳过它们。

解决方案¶

itertools 模�中有一些函数�以完�这个任务。 首先介�的是 itertools.dropwhile() 函数。使用时,你给它传递一个函数对象和一个�迭代对象。 它会返回一个迭代器对象,丢弃原有�列中直到函数返回Flase之�的所有元素,然�返回��所有元素。

为了演示,�定你在读�一个开始部分是几行注释的�文件。比如:

>>> with open('/etc/passwd') 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('/etc/passwd') as f:
...     for line in dropwhile(lambda line: not 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)
...
4
10
15
>>>

在这个例�中, islice() 函数最�那个 None �数指定了你�跳过��3个元素,获�第4个到最�的所有元素, 如果 None 和3的�置对调,��就是仅仅获��三个元素��相�, (这个跟切片的相��作 [3:] 和 [:3] 原�是一样的)。

讨论¶

函数 dropwhile() 和 islice() 其实就是两个帮助函数,为的就是��写出下�这�冗余代�:

with open('/etc/passwd') as f:
    # Skip over initial comments
    while True:
        line = next(f, '')
        if not line.startswith('#'):
            break

    # Process remaining lines
    while line:
        # Replace with useful processing
        print(line, end='')
        line = next(f, None)

跳过一个�迭代对象的开始部分跟通常的过滤是��的。 比如,上述代�的第一个部分�能会这样�写:

with open('/etc/passwd') as f:
    lines = (line for line in f if not line.startswith('#'))
    for line in lines:
        print(line, end='')

这样写确实�以跳过开始部分的注释行,但是�样也会跳过文件中其他所有的注释行。 ���讲,我们的解决方案是仅仅跳过开始部分满足测试�件的行,在那以�,所有的元素��进行测试和过滤了。

最�需���强调的一点是,本节的方案适用于所有�迭代对象,包括那些事先�能确定大�的, 比如生�器,文件�其类似的对象。