2012-03-29 81 views
2

我是Python的迭代器的新手,所以也许我的语言并不总是正确的。写访问迭代器?或者:将值发送到numpy数组的生成器

我有一个类包装的numpy.ndarray列表:

class wrapper: 
    def __init__(self, myList): 
     self.myList = myList 

    def getArrayIterator(self): 
     for arr in self.myList: 
      yield arr 

#set list of arrays in wrapper 
myList = [rand(3,3), rand(3,3), rand(3,3)] 
w = wrapper(myList) 

正如我的理解是,该第二方法返回发电机。 现在我想使用发电机来遍历列表和阵列恢复到别的东西:

for a in w.getArrayIterator(): 
    a = zeros((3,4)) 

我希望有通过这里引用语义通,但似乎并不如此。

所以我试图用Python的send()getArrayIterator功能:

# ... 
def getArrayIterator(self): 
    for arr in self.myList: 
     val = (yield arr) 
     if val is not None: 
      arr = val 
# ... 

但是,这不会工作,要么是因为:

a.send(zeros((3,4))) 
    AttributeError: 'numpy.ndarray' object has no attribute 'send' 

有一个简单的解决方案,实现我的期望行为? 我错过了什么吗?


编辑:有人向我指出,我应该提供有关我的实际问题的更多信息。上面的例子当然简化了。

我有一个列表numpy.ndarray列表表示一个张量T封装在我的班级。当访问T的一个元素时:t_ijkl我需要将存储在列表中的矩阵相乘:A(i)*B(j)*C(k)*D(l),第一个和最后一个是行/列向量。

所以有一组A,一组B,等等。每个属于我的应用程序中的一个网格点。

我现在想要在与每个网格点关联的矩阵上具有遍历所有网格点和迭代器的迭代器。

想到的第一个想法是使用迭代器C++风格来读取和写入矩阵。但正如agf指出的那样,这不是一个真正可行的方法。所以我想我会使用不同的迭代器来读取访问权限和专门的setter方法来为矩阵设置新的值。

+0

我不确定你想要做什么是一种好的做法。也许有更好的方法来达到你所需要的。你能提供一个你的输入数组和期望输出的例子吗? – 2012-03-29 08:55:54

+0

我不确定:D 整个类表示一个矩阵乘积状态,它是张量的某种分解方案,张量中的每个元素都表示为相关矩阵的乘积。例如,如果我有一个3阶张量,并且我想访问element_ijk,我实际上做了t_ijk = A(i)* A(j)* A(k)其中第一个和最后一个矩阵是行和列向量。每个索引i,j,k ...属于格上的物理索引,并且A矩阵存储在np.ndarray列表的列表中。所以我实际上需要两件事:... – 2012-03-29 09:29:29

+0

...第一:我想遍历各个物理网格点上的矩阵集合。第二:我想独立迭代给定站点上的各个矩阵。 – 2012-03-29 09:31:09

回答

2

我假设这是一个简化的例子,因为你有类的地方似乎没有理由不使用普通列表。

当你

name = somelist[0] 
name = 'other' 
你的对象 somelist指向名称 name第一个指数,然后在对象 'other'指向名称 name

。你永远不会指向somelist[0]'other'

所以除了send,您需要实际分配到列表:

class wrapper: 
    def __init__(self, myList): 
     self.myList = myList 

    def getArrayIterator(self): 
     for i, arr in enumerate(self.myList): 
      yarr = (yield arr) 
      if yarr is not None: 
       self.myList[i] = yarr 

#set list of arrays in wrapper 
myList = [1, 2, 3, 4, 5] 
w = wrapper(myList) 
witer = w.getArrayIterator() 
try: 
    a = next(witer) 
    for i in range(6, 11): 
     print a, 
     a = witer.send(i) 
except StopIteration: 
    pass 
print 
print w.myList 
+0

感谢这是有帮助的,尽管如此: 似乎我得到的AttributeError是因为我访问了我的for循环中已经解除引用的Iterator,这就是为什么你明确地写了循环。 有没有更好的方法来做到这一点?整个try catch构造类型使用迭代器击败了我的目的:这将是干净的代码,而不是加载循环和索引。 – 2012-03-29 09:21:10

+0

@MischaObrecht我认为因为'send'的工作方式,你将不得不使用'try' /'except'块。你还没有阐明为什么你不只是使用'list'--你不需要通过指示来访问它,你可以在你的课堂上正确显示你可以遍历它。我不明白你为什么要使事情变得复杂,或者为什么你需要更换白色的物品,你正在迭代它。 – agf 2012-03-29 09:32:18

+0

哦,是的,这是一个简化的例子,参见。我对上述最初问题的评论,如果你有兴趣。 Thx 如果我只使用列表,代码迟早会变成像列表[site_index] [first_physicalIndex] [secondPhysicalIndex] [rowIdx,colIdx]可怕的混乱... – 2012-03-29 09:34:05

-1

您只能使用发电机(yield关键字)读值不会写

+0

我知道,这就是为什么我试图__send( )__机制,这也不起作用。 (我只是想确保,每个人都可以在我的帖子的前半部分中了解我想要做的事情。) – 2012-03-29 08:40:57

+1

自从Py2.5以来,这是不正确的:http://docs.python.org/whatsnew/2.5.html#pep-342-new-generator-features – lvc 2012-03-29 08:40:59

0

听起来也许你想实施__getitem____setitem__

class wrapper: 
    def __init__(self, myList): 
     self.myList = myList  

    def __iter__(self): 
     for arr in self.myList: 
      yield arr  

    def __getitem__(self, key): 
     return self.myList[key] 

    def __setitem__(self, key, value): 
     self.myList[key] = value 

用法:

for index, arr in enumerate(w): 
    same_arr = w[index] 
    w[index] = zeros((3,4)) 

有很多其他有用的功能,如果你认为它会让你的生活更轻松,你可以实现。以下是关于模拟容器类型的documentation

+0

这并不能解释'发送',只是工作正如你使用'list'而不是用户定义的类一样。 – agf 2012-03-29 08:54:27

+0

@agf我对这个问题的理解是,包装类的目的是拦截对numpy数组的调用,并对它们做些什么,而不是仅仅了解生成器。我认为这是因为如果你只想玩发电机就不需要这个班。 – Dunes 2012-03-29 09:03:50

+0

可能。我没有猜测他的理由,但这是有道理的。 – agf 2012-03-29 09:07:33

相关问题