个性化阅读
专注于IT技术分析

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()实际上耗尽了它并立即产生了所有元素。


一个简单的演示:

>>> 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 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')
赞(0)
未经允许不得转载:srcmini » tuple()增加运行时间这么多是否正常?

评论 抢沙发

评论前必须登录!