filter函式與無限生成器結合使用遇到的問題

2021-09-18 07:18:35 字數 3009 閱讀 7905

python3中用於過濾序列,過濾掉不符合條件的元素,返回乙個迭代器物件,如果要轉換為列表,可以使用list()來轉換。 

廖雪峰關於filter的使用 很好的解釋了filter的作用,以及和生成器的結合,但是讓人疑惑的是:

it = filter(_not_divisible(n), it) #

構造新序列

以上這段**的具體實現細節是什麼?it是個生成器,使用filter對其進行操作的時候,並沒有陷入無限迴圈,難道是對當前已生成的所有資料進行操作?那為什麼在9這個數的時候,又能被已經跳過的3給濾除?有可能是filter給原有的it新增了判斷規則,在生成9這個數的時候,自動執行filter規則?帶著這個疑問,在官網的文章中並沒有找到合理的解釋。但是發現如下**可以使用同樣的功能,給了更多的思考線索。

from itertools import

filte***lse

def_odd_iter():

n = 1

while

true:

n = n + 2

yield

n

def_not_divisible(n):

return

lambda x: x % n ==0

defprimes():

yield 2it = _odd_iter() #

初始序列

while

true:

n = next(it) #

返回序列的第乙個數

yield

n it = filte***lse(_not_divisible(n), it) #

構造新序列

#列印1000以內的素數:

for n in

primes():

if n < 1000:

print

(n)

else

:

break

上述**依舊能生成所有的素數,而關於filte***lse的原始碼如下所示:

def

filte***lse(predicate, iterable):

#filte***lse(lambda x: x%2, range(10)) --> 0 2 4 6 8

if predicate is

none:

predicate =bool

for x in

iterable:

ifnot

predicate(x):

yield x

這段**依舊讓人覺得費解,為什麼filte***lse沒有返回值,it感覺確實被賦了值,這個值就行是什麼?又做了如下實驗:

a = [1, 2, 3, 4, 5]

a =iter(a)

b = filte***lse(lambda x: x%2==0, a)

print

(type(a))

print

(type(b))

print

(next(b))

print

(next(b))

print

(next(b))

輸出:'list_iterator

'>

'itertools.filte***lse

'>13

5

從中可以看出it是指向了itertools.filte***lse這個類的乙個例項,這個類是可迭代的,通過next(b)輸出了結果。b是生成器,a也是迭代器,在b的生成器函式裡使用迭代器a。

所以,原始**中filter重新賦值後的it是新的可迭代的型別,不是原始的生成器。就算是type(_odd_iter)也是,具有生成器功能的函式。

在primes迴圈while中,每次it會重新賦予乙個新的生成器,這個生成器巢狀了之前的生成器,是遞迴呼叫,最終的效果正如之前的猜想,相當於新增了規則,每次next的時候,對所有的規則遍歷一遍。具體的**執行是,每乙個生成器函式都儲存在記憶體中,乙個生成器函式又巢狀了上乙個生成器函式,每次next的時候,都會把之前所有的生成器函式遞迴一遍,等同於執行所有的規則。每執行一次訓練就會加一層巢狀,所有每次next的遍歷深度都在增加。

最後發現自己好蠢,it = filte***lse(_not_divisible(n), it) 這行**就是明顯的遞迴呼叫。

輸出:2

①it輸出:3

②it -> ①it

n=next(it) -> for x in ①iterable(相當於在原有生成器上執行了一次next) -> x=5,(判斷能被3整除嗎)yield 5  

n=5輸出:5

③it -> ②it -> ①it

n=next(it) -> for x in ②iterable -> for x in ①iterable -> x=7,(判斷能被3整除嗎)yield 7 -> ②iterable -> x=7,(判斷能被5整除嗎)yield 7

n=7輸出:7

④ -> ③it -> ②it -> ①it

n=next(it) -> for x in ③iterable  -> for x in ②iterable -> for x in ①iterable -> x=9 -> 能被3除去(沒有進入if,沒有執行yield,繼續for迴圈) -> x=11, (判斷能被3整除嗎)yield 11 -> ②iterable -> x=11, (判斷能被5除嗎)yield 11 -> ③iteable -> x=11, (判斷能被7整除嗎)yield 11 

n=11

輸出:11

在遞迴呼叫中,yield相當於return,for x in iterable相當於呼叫巢狀函式。每次產生新的資料都是從最原始_odd_iter()產生,每返回一層,就進行一次if規則判斷,通過判斷就不斷向上層返回,不通過就再次向最底層遍歷。

posted @

2018-12-04 17:06

mjl_cv 閱讀(

...)

編輯收藏

filter函式與無限生成器結合使用遇到的問題

python3中用於過濾序列,過濾掉不符合條件的元素,返回乙個迭代器物件,如果要轉換為列表,可以使用list 來轉換。廖雪峰關於filter的使用 很好的解釋了filter的作用,以及和生成器的結合,但是讓人疑惑的是 it filter not divisible n it 構造新序列 以上這段 的...

函式與生成器

一 函式屬性 函式可以在內部建立預設的屬性,還可以在外部通過句點屬性識別符號來動態建立該函式的屬性。def foo foo properly created doc string def bar pass foo.doc foo properly created doc string bar.doc...

函式與生成器

一 函式 1.1 函式的關鍵字 def 定義函式 return 返回值 pass 佔位 exit 1 直接退出並返回1 1.2 高階函式 高階函式都是可以通過 邏輯實現,但是自己寫的函式的複雜程度或者演算法不一定有人家內建的好 map高階函式 def f x return x x print map...