簡介
在Python/ target=_blank class=infotextkey>Python中,迭代器可以幫助你編寫更多Pythonic的代碼,并在處理長序列時提高效率。內置的itertools
模塊提供了幾個有用的函數來創建迭代器。
【itertools
】:https://docs.python.org/3/library/itertools.html
當你只需要遍歷迭代器、檢索序列中的元素并對其進行處理,而無需將它們存儲在內存中時,這些函數尤其有用。今天本文將學習如何使用以下四個itertools
過濾函數:
-
filterfalse
-
takewhile
-
dropwhile
-
islice
接下來跟隨本文開始吧!
在開始之前:關于代碼示例的說明
在本教程中:
我們將討論的所有四個函數都返回了迭代器。為了清楚起見,本文將使用簡單的序列,并使用list()
獲取包含迭代器返回的所有元素的列表。但在處理長序列時,除非必要,否則請不要這樣做,因為這樣做會失去迭代器帶來的內存節省。
對于簡單的謂詞函數,也可以使用lambdas
。但為了提高可讀性,本文將定義常規函數并將它們用作謂詞。
1. filterfalse
如果你在Python中編程已經有一段時間了,可能已經使用過內置的filter
函數,語法如下:
filter(pred,seq)
# pred:謂詞函數
# seq:任何有效的Python可迭代對象
filter
函數返回一個迭代器,該迭代器返回謂詞函數返回True
的序列中的元素。
示例如下:
nums = list(range(1,11)) #[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
def is_even(n):
return n % 2 == 0
在這里,nums
列表和is_even
函數分別是序列和謂詞。
要獲取nums
中所有偶數的列表,需要使用如下所示的filter
:
nums_even = filter(is_even, nums)
print(list(nums_even))
Output >>> [2, 4, 6, 8, 10]
現在跟隨本文來學習一下filterfalse
。本文將從itertools
模塊中導入filterfalse
函數(以及本文將要討論的所有其他函數)。
正如其名稱所示,filterfalse
執行與filter
函數相反的操作。它返回一個迭代器,該迭代器返回謂詞返回False
的元素。以下是使用filterfalse
函數的語法:
from itertools import filterfalse
filterfalse(pred,seq)
is_even
函數對于nums
中的所有奇數返回False
。因此,使用filterfalse
得到的nums_odd
列表是nums
中所有奇數的列表:
from itertools import filterfalse
nums_odd = filterfalse(is_even, nums)
print(list(nums_odd))
Output >>> [1, 3, 5, 7, 9]
2. takewhile
使用takewhile
函數的語法如下:
from itertools import takewhile
takewhile(pred,seq)
takewhile
函數返回了一個迭代器,只要謂詞函數返回True
,它就會返回元素。當謂詞函數第一次返回False
時,它就停止返回元素。
對于長度為n的序列,如果seq[k]
是第一個使謂詞函數返回False
的元素,則迭代器會返回seq[0]
、seq[1]
、...、seq[k-1]
。
考慮以下的nums
列表和謂詞函數is_less_than_5
。本文使用takewhile
函數,如下所示:
from itertools import takewhile
def is_less_than_5(n):
return n < 5
nums = [1, 3, 5, 2, 4, 6]
filtered_nums_1 = takewhile(is_less_than_5, nums)
print(list(filtered_nums_1))
在這里,謂詞is_less_than_5
對于數字5
首次返回False
:
Output >>> [1, 3]
3. dropwhile
從功能上講,dropwhile
函數的作用與takewhile
函數相反。
以下是如何使用dropwhile
函數的示例:
from itertools import dropwhile
dropwhile(pred,seq)
dropwhile
函數返回一個迭代器,只要謂詞為True
,該迭代器就會持續刪除元素。也就是說,迭代器在謂詞第一次返回False
之前不返回任何元素。一旦謂詞返回False
,迭代器就會返回序列中的所有后續元素。
對于長度為n的序列,如果謂詞函數第一次返回False
的元素是seq[k]
,那么迭代器會返回seq[k]
、seq[k+1]
、…、seq[n-1]
。
接下來使用相同的序列和謂詞函數:
from itertools import dropwhile
def is_less_than_5(n):
return n < 5
nums = [1, 3, 5, 2, 4, 6]
filtered_nums_2 = dropwhile(is_less_than_5, nums)
print(list(filtered_nums_2))
由于謂詞函數is_less_than_5
第一次返回False
是在元素5上,因此本文得到從5開始的序列中的所有元素:
Output >>> [5, 2, 4, 6]
4. islice
你可能已經熟悉了對Python可迭代對象(如列表、元組和字符串)進行切片操作。切片的語法是:iterable[start:stop:step]
。
然而,這種切片操作具有以下缺點:
-
在處理大型序列時,每個切片或子序列都是一個占用內存的副本,這可能會降低效率。
-
由于步長也可以取負值,使用起始、停止和步長值會影響可讀性。
islice
函數解決了上述限制:
-
它返回一個迭代器。
-
它不允許步長取負值。
可以按以下方式使用islice
函數:
from itertools import islice
islice(seq,start,stop,step)
下面是使用islice
函數的幾種不同方式:
-
使用
islice(seq, stop)
函數返回一個迭代器,該迭代器遍歷切片seq[0]
、seq[1]
、...、seq[stop - 1]
。 -
如果指定了起始和停止值:
islice(seq, start, stop)
,該函數會返回一個迭代器,該迭代器遍歷切片seq[start]
、seq[start + 1]
、...、seq[start + stop - 1]
。 -
當指定起始、停止和步長參數時,該函數返回一個迭代器,該迭代器遍歷切片
seq[start]
、seq[start + step]
、seq[start + 2*step]
、...、seq[start + k*step]
,其中start + k*step < stop
且start + (k+1)*step >= stop
。
接下來以一個示例列表來更好地理解這個問題:
nums = list(range(10)) #[0,1, 2, 3, 4, 5, 6, 7, 8, 9]
現在,跟隨本文使用已學過的islice
函數的語法。
僅使用停止值
這里本文只指定停止索引:
from itertools import islice
# 僅指定停止索引
sliced_nums = islice(nums, 5)
print(list(sliced_nums))
以下是輸出結果:
Output >>> [0, 1, 2, 3, 4]
使用起始和停止值
在這里,本文同時使用起始值和停止值:
# 指定起始和停止索引
sliced_nums = islice(nums, 2, 7)
print(list(sliced_nums))
切片從索引2開始,一直延伸到索引7但不包括索引7:
Output >>> [2, 3, 4, 5, 6]
使用起始、停止和步長值
當本文使用起始、停止和步長值時:
# 使用起始、停止和步長
sliced_nums = islice(nums, 2, 8, 2)
print(list(sliced_nums))
得到一個從索引2開始、一直延伸到索引8但不包括索引8的切片,步長為2(每隔一個元素返回一次))。
Output >>> [2, 4, 6]
總結
希望本教程能幫助你理解itertools
過濾函數的基礎知識。通過查看一些簡單的示例,可以更好地理解這些函數的工作原理。