2017-03-01 13 views
3

考慮這兩個功能:爲什麼不能用kwarg切換函數發生器的行爲?

def foo(): 
    x = 0 
    while True: 
     yield x 
     x += 1 

def wrap_foo(limit=10, gen=True): 
    fg = foo() 
    count = 0 
    if gen: 
     while count < limit: 
      yield next(fg) 
      count += 1 
    else: 
     return [next(fg) for _ in range(limit)]= 

foo()是發電機,並wrap_foo()只是把多少數據獲取生成的限制。我正在嘗試讓包裝器像gen=True一樣生成一個生成器,或者作爲一個常規函數,將所有生成的數據直接與kwarg gen=False一起存儲到內存中。

經常發生的行爲可以作爲我期望:

In [1352]: [_ for _ in wrap_foo(gen=True)] 
Out[1352]: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 

然而,隨着gen=False說,沒有東西產生。

In [1351]: [num for num in wrap_foo(gen=False)] 
Out[1351]: [] 

好像Python的預分類的功能以基於yield語句的存在的發電機(後者例如,如果yield被註釋了完美地工作)。

這是爲什麼?我想了解這裏的機制。我跑3.6

+0

如果在你的'def'中有一個'yield',那麼這個函數將永遠是一個生成器*。一個'return'將作爲一個隱含的'StopIteration',而不是一個典型的'return'值。如果你想把整個東西加載到內存中,只需使用'list(wrap_foo(10))'。你爲什麼要以其他方式來做? –

+0

這就是我的想法。我只是在我的交互式shell中一度懶惰,並試圖添加一個kwarg,所以我可以直接獲取生成的數據,而不是總是調用'[_ for _ in ...'然後我有些奇怪,爲什麼我不能去做。 –

+0

但是你不需要*調用'[_ for _ in ...]',你已經將該邏輯抽象爲一個生成器,所以要實現它只是使用'list' –

回答

5

好像Python的預分類基礎上,產量聲明

是存在的功能作爲發電機,這正是發生了什麼。 wrap_foo被確定爲功能定義時間的發生器。你可以考慮使用生成器表達式來代替:

def wrap_foo(limit=10, gen=True): 
    fg = foo() 
    if gen: 
     return (next(fg) for _ in range(limit)) 
    else: 
     return [next(fg) for _ in range(limit)] 
3

好像Python的功能作爲yield語句存在基於 (後者例如完美的作品 如果產量被註釋掉)發電機預分類。

這是爲什麼?

因爲Python不能等到函數實際執行yield來決定它是否是生成器。首先,生成器被定義爲不執行任何的代碼,直到第一個next。其次,如果生成器恰好不生成任何元素,則生成器可能永遠不會實際到達其任何yield語句。

相關問題