2015-10-07 132 views
3

我想要创建一个返回数组的动态生成器。例如:使用numpy数组的Python生成器

import numpy as np 
def my_gen(): 
    c = np.ones(5) 
    j = 0 
    t = 10 
    while j < t: 
     c[0] = j 
     yield c 
     j += 1 

用一个简单的循环:

for g in my_gen(): 
    print (g) 

我得到了我想要的东西。但与list(my_gen()),我得到了一个列表,其中总是包含相同的东西。

我挖得更深一些,我发现,当我yield c.tolist()代替yield c,一切都OK了...

我只是无法解释自己是如何来到这个奇怪的现象...

回答

6

这是因为c总是指向相同的numpy数组引用,您只需更改生成器函数中的c中的元素。

只需打印时,它会在该特定时刻打印完整的c数组,因此您可以正确地获取打印值。

但是,当您使用list(my_gen())时,您会不断向列表添加与c numpy数组相同的引用,因此对该numpy数组的任何更改也反映在列表中以前添加的元素中。

当你做yield c.tolist(),因为创建从numpy的数组一个新的列表,因此您不断添加新的列表对象在未来clist,从而改变了以前添加名单并不反映它为你的作品。

+0

太棒了!谢谢你的回答:) – XXXXXL

0

好吧,我想是因为在这个生成器中,因为我返回的是同一个引用,所以生成器的产量总是相同的。如果我yield np.array(c),这将工作...

3

一个替代发电机返回列表的副本。我保留np.ones()作为创建号码的便捷方式,但立即将其转换为列表(仅一次)(array.tolist()相对昂贵)。

我收益c[:],以避免'当前版本'的问题。

def gen_c(): 
     c = np.ones(5,dtype=int).tolist() 
     j = 0 
     t = 10 
     while j < t: 
       c[0] = j 
       yield c[:] 
       j += 1 


In [54]: list(gen_c()) 
Out[54]: 
[[0, 1, 1, 1, 1], 
[1, 1, 1, 1, 1], 
[2, 1, 1, 1, 1], 
[3, 1, 1, 1, 1], 
[4, 1, 1, 1, 1], 
[5, 1, 1, 1, 1], 
[6, 1, 1, 1, 1], 
[7, 1, 1, 1, 1], 
[8, 1, 1, 1, 1], 
[9, 1, 1, 1, 1]] 
In [55]: np.array(list(gen_c())) 
Out[55]: 
array([[0, 1, 1, 1, 1], 
     [1, 1, 1, 1, 1], 
     [2, 1, 1, 1, 1], 
     [3, 1, 1, 1, 1], 
     [4, 1, 1, 1, 1], 
     [5, 1, 1, 1, 1], 
     [6, 1, 1, 1, 1], 
     [7, 1, 1, 1, 1], 
     [8, 1, 1, 1, 1], 
     [9, 1, 1, 1, 1]]) 
+0

谢谢soooo多!这确实提高了很多的表现!大! – XXXXXL