Effective Python – 例36 使用itertools幫助iterators與generators

當使用iterator寫一些刁鑽的程式碼時,itertools也許會有現成的工具。

import itertools

it = itertools.chain([1, 2, 3], [4, 5, 6])
print(list(it))
# [1, 2, 3, 4, 5, 6]

it = itertools.repeat('hello', 3)
print(list(it))
# ['hello', 'hello', 'hello']

it = itertools.cycle([1, 2])
result = [next(it) for _ in range(10)]
print(result)
# [1, 2, 1, 2, 1, 2, 1, 2, 1, 2]

it1, it2, it3 = itertools.tee(['first', 'second'], 3)
print(list(it1))
print(list(it2))
print(list(it3))
['first', 'second']
['first', 'second']
['first', 'second']

tee可以平行生出多個iterators,但要小心記憶體可能會使用很多。

keys = ['one', 'two', 'three']
values = [1, 2]

normal = list(zip(keys, values))
print('zip: ', normal)

it = itertools.zip_longest(keys, values, fillvalue='nope')
print('zip_longest:', list(it))

zip_longest類似內建的zip,只是zip會以最短的iterator回傳,而zip_longest會以最長的iterator回傳。預設會以None來補上缺值。

zip:  [('one', 1), ('two', 2)]
zip_longest: [('one', 1), ('two', 2), ('three', 'nope')]
values = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

first_five = itertools.islice(values, 5)
print('First five: ', list(first_five))

middle_odds = itertools.islice(values, 2, 8, 2)
print('Middle odds:', list(middle_odds))
First five:  [1, 2, 3, 4, 5]
Middle odds: [3, 5, 7]

islice可以做出類似list的slice功能

values= [1, 2, 3, 4, 5, 4, 3, 2, 1]
it = itertools.takewhile(lambda x: x < 4, values)
print(list(it))
[1, 2, 3]

takewhile需要傳入一個callable object,當其回傳為False會停止iterator。另外有一個dropwhile會從其回傳True的時候開始iterator。

evens = lambda x: x % 2 == 0

filter_result = filter(evens, values)
print('Filter: ', list(filter_result))

filter_false_result = itertools.filterfalse( evens, values)
print('Filter false: ', list(filter_false_result))
Filter:  [2, 4, 4, 2]
Filter false:  [1, 3, 5, 3, 1]

filter_false就是內建的filter的相反。

發表留言

這個網站採用 Akismet 服務減少垃圾留言。進一步瞭解 Akismet 如何處理網站訪客的留言資料