一般来说,yield 和append 哪个更快?

问题描述 投票:0回答:5

我目前正在进行一个个人学习项目,在 XML 数据库中进行阅读。我发现自己正在编写收集数据的函数,但我不确定返回它们的快速方法是什么。

哪个通常更快:

  1. yield
    s,或
  2. 函数内有多个
  3. append()
    ,然后是 
    return
     接下来的 
    list
我很高兴知道在什么情况下

yield

会比
append()
更快,反之亦然。

python performance return generator yield
5个回答
25
投票

yield

具有“懒惰”的巨大优势,而速度通常不是使用它的“最佳”原因。但如果它在您的环境中有效,那么就没有理由不使用它:
# yield_vs_append.py data = range(1000) def yielding(): def yielder(): for d in data: yield d return list(yielder()) def appending(): lst = [] for d in data: lst.append(d) return lst 这是结果:

python2.7 -m timeit -s "from yield_vs_append import yielding,appending" "yielding()" 10000 loops, best of 3: 80.1 usec per loop python2.7 -m timeit -s "from yield_vs_append import yielding,appending" "appending()" 10000 loops, best of 3: 130 usec per loop

至少在这个非常简单的测试中,

yield

比追加更快。
    

我最近问了自己一个类似的问题,探索通过附加到列表或通过生成器来生成列表(或元组)的所有排列的方法,并发现(对于长度为 9 的排列,需要大约一秒钟左右的时间才能生成):


10
投票
itertools.permutations

时间的三倍
    使用发电机(即
  • yield
    )可以减少大约。 20%
  • 使用生成器生成元组是最快的,大约是
  • itertools.permutations
    时间的两倍。
  • 加一粒盐一起服用!计时和分析非常有用:
    
    
    if __name__ == '__main__': import cProfile cProfile.run("main()")

TH4Ck 的yieling() 有一个更快的替代方案。这是列表理解。

In [245]: def list_comp(): .....: return [d for d in data] .....: In [246]: timeit yielding() 10000 loops, best of 3: 89 us per loop In [247]: timeit list_comp() 10000 loops, best of 3: 63.4 us per loop

6
投票
当然,在不知道代码结构的情况下对这些操作进行微基准测试是相当愚蠢的。它们每个在不同的情况下都有用。例如,如果您想应用可以表达为单个表达式的简单操作,列表理解非常有用。 Yield 有一个显着的优势,可以让你将遍历代码隔离到生成器方法中。哪一种合适很大程度上取决于用途。

首先你必须决定,如果你需要生成器,这也得到了改进的方法。就像列表生成器“[elem for elem in somethink]”。如果您只使用列表中的值进行某些操作,建议使用生成器。但是,如果您需要列表进行许多更改,并同时处理许多元素,则必须是列表。
(就像标准程序员使用列表的 70% 次一样,生成器会更好。使用更少的内存,只是很多人看不到列表的其他方式。不幸的是,在我们这个时代,许多人对良好的优化嗤之以鼻,而只是为了工作.)

如果你使用列表生成器来提高回报,那么让我们对收益人员做同样的事情。不管怎样,我们为 Python 编程语言中的所有操作提供了多种更优化的方法。

0
投票
产出比回报更快,我会证明这一点。 只要检查一下这些人:

data = range(1000) def yielder(): yield from data def appending(): L = [] app = list.append for i in data: app(L, i) return L def list_gen(): return [i for i in data]

当然,追加会比其他想法慢,因为我们创建并扩展列表任何循环时间。只是循环“for”是非常不优化的,如果你可以避免这个,那就这样做。因为在任何步骤中,该函数都会加载下一个元素并写入我们的变量,以在内存中获取该对象值。所以我们跳转到任何元素,创建引用,在循环中扩展列表(声明的方法是巨大的速度优化器),当我们生成返回时,摘要在两个列表中得到了 2000 个元素。

list_gen 不太节省内存,我们只返回元素,但像 up 一样,我们生成第二个列表。现在我们得到了两个列表,原始数据和她的副本。总结2000个要素。只是我们避免了创建变量引用的步骤。因为我们的列表中的生成避免了这一步。只需写元素即可。

yielder 使用的内存最少,因为我们刚刚从数据中获得了值。我们避免提及任何一项。例如:

data = range(1000) def yielder(): yield from data def list_gen(): return [i for i in data] #Now we generate next reference after line [i for i in data] for i in list_gen(): #some instruction #This is our first reference, becouse was yield from data. for i in yielder(): #some instruction

某些指令仅使用一个元素,而不是全部来自列表,下一个值生成器将在下一个循环中返回,而不是杂志所有 1000 个元素写入引用。

抱歉,这个话题有点挖掘,就在我不小心从谷歌搜索中交叉出来的时候,其他初学者Python程序员都可以看到这个废话。
    

关于

yield

的快速说明,它不是持久的。缺乏持久性会让新开发人员感到困惑 -

0
投票
- 开发人员,这可能会使你的代码变慢:

def count_to_five(): for i in range(5): yield i + 1 five_count = count_to_five() print(list(five_count)) # [1, 2, 3, 4, 5] # What? I didn't do anything. I just printed the result again! print(list(five_count)) # [] 我意识到这不是您好奇的“速度”,但开发速度是使用列表或生成器时要考虑的一个指标。这也不是一个病态的例子;有人可能使用打印语句来调试结果,但没有意识到他们这样做正在改变结果。

© www.soinside.com 2019 - 2024. All rights reserved.