tuple()增加运行时间这么多是否正常()

我有一个相对较长(20, 000行)的CSV文件, 并且编写了一个简单的函数来打开它:

def read_prices(): with open('sp500.csv', 'r') as f: reader = csv.DictReader(f) for row in reader: yield float(row['Adj Close'].strip())

当我按原样计时时, 它需要3e-05s:
print(timeit.timeit(lambda: read_prices('SP500.csv'), number=100))

当我使用相同的函数但使用tuple(… )时, 它要花费高达27秒的时间:
print(timeit.timeit(lambda: tuple(read_prices('SP500.csv')), number=100))

这对tuple()正常吗?为什么会这样呢?我是一个初学者, 所以欢迎使用ELI5解释:)
#1发生这种情况是因为read_prices不是函数-实际上是生成器。那是因为yield关键字。
如功能编程HOWTO中所述:
任何包含yield关键字的函数都是生成器函数;这是由Python的字节码编译器检测到的, 该编译器因此专门编译了该函数。调用生成器函数时, 它不会返回单个值;而是返回一个支持迭代器协议的生成器对象。
因此, 当你运行第一个read_prices(‘ SP500.csv’ )时, 会发生什么, 只是创建生成器对象, 等待被告知产生元素。
在第二个版本tuple(read_prices(‘ SP500.csv’ ))中, 你像以前一样创建了生成器对象, 但是tuple()实际上耗尽了它并立即产生了所有元素。
【tuple()增加运行时间这么多是否正常()】一个简单的演示:
> > > 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)

#2这是因为这是一个生成器read_prices(‘ SP500.csv’ ), 当这样调用时, 它几乎什么也不做。
但是, 当你执行此元组(read_prices(‘ SP500.csv’ ))时, 它将操作生成器并提供值。
生成器是可迭代的, 其作用是:
  • for循环
  • 下一个
  • 使用元组(如你所述)打开包装或列出
在其他涉及集合构造的操作中。
这是生成器的一个更具体的示例:
def f(): print("First value:") yield "first" print("Second value:") yield "second"

它在起作用:
### Nothing prints when called (analogous to your first timeitwithout 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')

    推荐阅读