天天看點

python cookbook 學習筆記 第四章 疊代器和生成器(8) 跳過可疊代對象的開始部分

  • 跳過可疊代對象的開始部分
  • 問題:
    • 想周遊一個可疊代對象,但是它開始的某些元素并不感興趣,想跳過它們。
  • 解決方案:
    • 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= "")
           
  • 這樣寫的話,确實可以跳過開始部分的注釋行,但是同樣也跳過檔案中其他所有的注釋行。
  • 本節的案例使用所有可疊代對象,包括事先不能确定大小的,比如疊代器,檔案及類似對象。