2 回答

TA貢獻(xiàn)1840條經(jīng)驗(yàn) 獲得超5個贊
發(fā)生這種情況是因?yàn)?code>read_prices它不是一個函數(shù) - 它實(shí)際上是一個generator
. 那是因?yàn)?code>yield關(guān)鍵字。
正如函數(shù)式編程 HOWTO中所解釋的:
任何包含yield關(guān)鍵字的函數(shù)都是生成器函數(shù);這是由 Python 的字節(jié)碼編譯器檢測到的,該編譯器專門編譯該函數(shù)作為結(jié)果。
當(dāng)您調(diào)用生成器函數(shù)時,它不會返回單個值;相反,它返回一個支持迭代器協(xié)議的生成器對象。
所以當(dāng)你第一次運(yùn)行時發(fā)生的read_prices()
只是一個generator
對象的創(chuàng)建,等待被告知yield
元素。
在第二個版本中tuple(read_prices())
,您像以前一樣創(chuàng)建generator
對象,但tuple()
實(shí)際上會一次性耗盡它和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貢獻(xiàn)1821條經(jīng)驗(yàn) 獲得超6個贊
這是因?yàn)檫@是一個生成器 read_prices('SP500.csv')
,當(dāng)這樣調(diào)用時它幾乎什么都不做。
但是,當(dāng)您這樣做時,tuple(read_prices('SP500.csv'))
它會操作生成器并提供值。
生成器是可迭代的,由 a 操作:
for 循環(huán)
下一個
使用解包
tuple
(如您所述)或list
在涉及集合構(gòu)造的其他操作中。
這是一個更具體的生成器示例:
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')
添加回答
舉報(bào)