【python學習筆記】33:生成器、迭代器、高階函式
生成器
生成器(generator)相比列表推導式,只佔用很小的空間,因為它是一邊迴圈一邊推算,通過next()
呼叫下一元素,並在結束時丟擲StopIteration
異常,在語法上只要把[]
換成()
即可。
a = (i * i for i in range(10))
print(a) # 生成器物件,不能直接輸出
# 用"next(生成器)"或者"生成器.__next__()"來返回下一個元素
print(a.__next__()) # 0
print(next(a)) # 1
for x in a: # for本身也是在一個一個呼叫next()
print(x, end=' ' ) # 輸出剩下的4 9 16 25 36 49 64 81
可以在函式內使用yield
關鍵字將該函式變成一個generator,每次呼叫next()
時執行,執行到yield
時候暫停下來並返回yield
後跟的值,下次呼叫next()
時繼續從剛剛暫停的yield
語句的下一句繼續執行。
當某個next()
呼叫沒有遇到yield
就已經結束了整個函式時,就會丟擲StopIteration
異常,而不需要raise StopIteration()
。
迭代器
可以依次訪問元素(即可以用for
迴圈遍歷)的是可迭代物件(Iterable
);可以用next()
依次訪問的可迭代物件是迭代器(Iterator
)。
生成器一定是迭代器,list
、dict
、str
是可迭代物件,但不是迭代器,可以iter()
函式轉成迭代器。
from collections import Iterable, Iterator
a = [i for i in range(5)] # 這是一個list
print(isinstance(a, Iterable)) # True,即可迭代
print(isinstance(a, Iterator)) # False,即不是迭代器
b = iter(a) # 轉換為迭代器
print(b.__next__()) # 0
print(b.__next__()) # 1
for n in b:
print(n, end=' ') # 2 3 4
高階函式
函式可以傳給變數,也可以像普通變數一樣當做引數傳給函式,接受函式為引數的函式就是高階函式。
map()
高階函式map()
接收一個函式,再接受一個Iterable
,將函式作用在Iterable
中的每個元素上,將返回值組成一個惰性Iterator
序列並返回。
def fun(n):
return n / 2
a = [i * i for i in range(5)] # 可迭代物件(Iterable)
b = map(fun, a) # 返回一個迭代器(Iterator)
print(list(b)) # [0.0, 0.5, 2.0, 4.5, 8.0]
reduce()
高階函式reduce()
接收一個函式,再接受一個Iterable
,將函式作用在Iterable
中的前兩個元素上,將返回值與下一個元素一起再扔給該函式,如此反覆。
from functools import reduce
# 傳給reduce的函式要接收兩個引數
def fun(m, n):
return m + n
a = [i * i for i in range(5)] # 可迭代物件(Iterable)
b = reduce(fun, a) # 反覆進行兩兩計算,最終返回計算結果
print(b) # 30
filter()
高階函式filter()
的輸入輸出形式和map()
一樣,不過filter()
是將傳入的函式作用到Iterable
的每個元素上,最終只保留返回True
的那些元素。也就是過濾掉一些元素,返回原Iterable
的一個帶序子集。
from collections import Iterable, Iterator
def fun(n):
if n < 2:
return False
if n < 4:
return True
i = 2
while i * i <= n:
if 0 == n % i:
return False
i += 1
return True
a = range(50) # Iterable
# print(isinstance(a, Iterator)) # False
b = filter(fun, a) # 返回過濾後的Iterator
# print(isinstance(b, Iterator)) # True
print(list(b)) # [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47]
sorted()
Java或者C++的排序可以指定一個比較器或者自定義比較大小的函式,在Python裡只是指定其key
引數為某個函式,這個函式對排序的元素做一定的變換,使元素按照變換後的值來進行排序,但並未指定比較規則。
a = [3, -2, 8, -6, 0, 4, -9]
b = sorted(a, key=abs, reverse=True) # 按絕對值從大到小排序
print(b) # [-9, 8, -6, 4, 3, -2, 0]