2010-08-15 61 views
12

我目前正在一个个人学习项目中阅读XML数据库。我发现自己正在编写收集数据的函数,我不确定什么是快速返回它们的方法。哪个速度通常更快,收益率还是附加值?

一般是快:

  1. yield S,或
  2. 几个append() S中的函数,那么return随后list内?

我会很高兴知道在什么情况下yield s会比append() s更快,反之亦然。

回答

15

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比追加快。

+1

_lazy_是否表示_low memory requirement_? – Kit 2010-08-26 03:41:46

+2

我写了一个WKdm算法的压缩器/解压缩器。在分析将这些比特解包到列表中的一个函数后,分析速度最慢。我把它转换成了一个发生器,而且速度更慢。产量版本提供约22MB/s,附加版本提供约38MB/s。所以这真的取决于你在做什么。 – Christopher 2013-06-16 13:57:01

+2

'lst.append'查找可能会减慢'appending()'。您可以在循环之外使用'append = lst.append'来尝试。 – jfs 2014-09-22 12:26:26

7

我最近问自己一个类似的问题,探索通过追加到列表或通过生成器来生成列表(或元组)的所有排列的方法,并发现(对于长度为9的排列,需要大约一秒钟或这样就可以生成):

  • 简易方法(排列的列表,追加到列表,列表返回列表)大约需要三次使用发电机的itertools.permutations
  • 时间(即yield)降低约这。 20%
  • 使用发生器和产生的元组是最快的,的itertools.permutations约两倍的时间。

用一粒盐拿!计时和分析非常有用:

if __name__ == '__main__': 
    import cProfile 
    cProfile.run("main()") 
6

TH4Ck的yielding()有更快的选择。这是列表理解。

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 

当然,在不知道代码结构的情况下对这些操作进行微观基准测试是相当愚蠢的。他们每个人都在不同的情况下有用。例如,如果您想要应用可以表达为单个表达式的简单操作,则列表理解很有用。对于您将遍历代码隔离为生成器方法,收益率具有显着的优势。哪一个合适取决于使用情况。

+0

我其实想要包含列表解析,但是我在这两者之间选择:'[n for func_that_yields()]''或'[for n in func_that_returns_an_iterable()]''。请注意,'n'可以是一个简单的元素解包,或者一个复杂的元素操作。无论如何,你有好点:) – Kit 2010-08-16 11:15:11

0

Primallyü必须决定,如果u需要发电机,这也得到了改进的方法。像列表生成器“[elem for somethink]”。如果你在列表中使用某些操作的值,那么推荐使用生成器。但是如果你需要列出许多变化,并且同时处理很多元素,那么这个列表必须是列表。 (如果标准程序员使用列表为70%时间,则更好的是发生器。使用较少的内存,很多人只是看不到其他方式的列表。不幸的是,在我们这个时代,许多人认为optymalization很好,只是为了工作。)

如果你使用发电机列表来提高回报,让我们对收益人做同样的事情。无论如何,我们为Python编程语言中的所有操作提供了多个更优化的方法。

收益率回报较快,我会证明这一点。 只是检查这个家伙:

当然
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] 

中追加会比较慢,然后其他的想法,becouse我们创建和扩展列表中的任何循环时间。只是循环“for”是非常unoptymalized,如果你可以避免这样做,那样做。如果在任何步骤中都有此参数,则加载下一个元素并写入我们的变量,以便在内存中获取此对象值。所以我们跳到任何元素上,在循环中创建引用,扩展列表(声明的方法是巨大的速度optymalizer),当我们生成返回时,汇总在两个列表中获得了2000个元素。

list_gen的内存不足,我们只是返回元素,但像起来一样,我们生成了secound列表。现在我们有两个名单,原始数据和她的副本。摘要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 

只使用一个元素的一些指令,并非所有从列表中,下一个价值yielder将返回在下一循环,而不是杂志所有1000个元素的参考来写。

对于小挖的话题,只是当我不小心从谷歌搜索来了一个交叉,其他初学python程序员可以看到这个废话。