2 回答

TA貢獻1840條經驗 獲得超5個贊
發生這種情況是因為read_prices
它不是一個函數 - 它實際上是一個generator
. 那是因為yield
關鍵字。
正如函數式編程 HOWTO中所解釋的:
任何包含yield關鍵字的函數都是生成器函數;這是由 Python 的字節碼編譯器檢測到的,該編譯器專門編譯該函數作為結果。
當您調用生成器函數時,它不會返回單個值;相反,它返回一個支持迭代器協議的生成器對象。
所以當你第一次運行時發生的read_prices()
只是一個generator
對象的創建,等待被告知yield
元素。
在第二個版本中tuple(read_prices())
,您像以前一樣創建generator
對象,但tuple()
實際上會一次性耗盡它和yield
所有元素。
一個簡單的演示:
>>> def yielder():
... yield from [1, 2, 3]
...
>>> y = yielder()
>>> y
<generator object yielder at 0x2b5604090de0>
>>> next(y)
1
>>> list(y)
[2, 3]
>>> tuple(yielder())
(1, 2, 3)

TA貢獻1821條經驗 獲得超6個贊
這是因為這是一個生成器 read_prices('SP500.csv')
,當這樣調用時它幾乎什么都不做。
但是,當您這樣做時,tuple(read_prices('SP500.csv'))
它會操作生成器并提供值。
生成器是可迭代的,由 a 操作:
for 循環
下一個
使用解包
tuple
(如您所述)或list
在涉及集合構造的其他操作中。
這是一個更具體的生成器示例:
def f():
print("First value:")
yield "first"
print("Second value:")
yield "second"
這是在行動:
### Nothing prints when called (analogous to your first timeit without tuple)
In [2]: v = f()
In [3]:
### However when I call `next` the first value is provided:
In [3]: next(v)
First value:
Out[3]: 'first'
## etc, until there is no more values and a "StopIteration` exception is raised:
In [4]: next(v)
Second value:
Out[4]: 'second'
In [5]: next(v)
------------------------------------
...
StopIteration:
## by unpacking using "tuple" the "StopIteration"
## exception is handled and all the values are provided at once
## (like your timeit using the tuple):
In [6]: tuple(f())
First value:
Second value:
Out[6]: ('first', 'second')
添加回答
舉報