在Python中嵌套生成器更好吗?

时间:2014-09-01 08:00:20

标签: python python-3.x

好的,所以我尝试阅读了几个来源:OneTwoThree。第一个来源明确指出使用生成器表达式可以节省内存,并使事情变得更快。但是当它们嵌套时会发生什么?这是一个例子,我希望有人能够帮助我理解它。

In  [1]: def nested():
             [(ix, '-'.join(str(x) for x in hours)) for ix in table.index.get_level_values(0)]
         %timeit nested
Out [1]: 10000000 loops, best of 3: 33.5 ns per loop

In  [2]: def not_nested():
             hr = '-'.join(str(x) for x in hours) #hr = 7-8
             [(ix, hr) for ix in table.index.get_level_values(0)]
         %timeit not_nested
Out [2]: 10000000 loops, best of 3: 38.7 ns per loop

在上面的例子中,hours是一个列表2个元素长,而table在0级的索引数是32。

如果我要在脑海中运行这两个函数,我会假设在函数nested中,元组的后半部分('-'.join(str(x) for x in hours)将被称为“外部”的多次(ix)循环运行(这与table中的索引一样多)。但是,在函数not_nested中,元组的后半部分被初始化一次(存储在hr中),并且每次执行第二行时都不会运行。

首先,我认为Python的工作原理是正确的吗?如果我,那么任何人都可以解释嵌套函数的运行时间是如何短于没有嵌套的运行时间?

开始编辑/解决方案

显然,我在调用函数时犯了一个错误,因为这两个答案启发了。我使用正确的函数调用重新运行timeit,并得到了预期的结果:

In  [1]: %timeit nested()
Out [1]: 10000 loops, best of 3: 55.5 µs per loop

In  [2]: %timeit not_nested()
Out [2]: 100000 loops, best of 3: 4.53 µs per loop

最终,在嵌套时没有嵌套运行时的一小部分时使运行时。感谢大家的回答和清除!

结束修改

2 个答案:

答案 0 :(得分:2)

您没有测量调用该函数的时间,您正在测量查找当前范围内函数名称的时间。

尝试%timeit nested()

至于为什么会出现时间上的差异 - 很容易说"因为第二个名称更长,所以哈希查找中的字符串比较需要更长时间"但是我不认为这实际上是正确的,因为(我认为)所涉及的字符串无论如何都会被CPython拦截。当然,我不能让Python在我自己的测试中一直报告更长的时间来查找更长的函数名。

如果您对查询时间感兴趣,请先运行多次,然后查看数字的一致性。

答案 1 :(得分:1)

您计算从命名空间中检索函数所需的时间。命名空间是一个字典,为了在字典中搜索某些东西,python必须调用键上的hash函数(函数名)。

较长的密钥需要更多时间来生成哈希值,因此您看到的增量值是因为nested是6个字母,而not_nested是10个字母。尝试切换名称,神奇地根据您的测试,较慢的功能会变得更快。为了给函数计时,你必须调用它:

%timeit nested()
%timeit not_nested()