在Python中......
我在类中定义了一个嵌套列表:
self.env = [[ None for i in range(columnCount)] for j in range(rowCount) ]
出于这个问题的目的,我们假设这个嵌套列表包含以下值:
[None, None, None, None]
[None, None, None, None]
[None, None, 0, None]
[None, None, None, None]
我需要能够利用 iter 和next()方法按列主要顺序(row0,col0 row1,col0,row2,col0 ......)浏览此列表。< / p>
目的是让它将位于该网格位置的值发送到另一个函数以进行处理。
到目前为止,我将 iter 函数定义为:
def __iter__(self):
return iter(self.env)
然后我将下一个函数定义为:
def next(self):
self.currentRow += 1
self.currentColumn += 1
if ( (self.currentRow < self.getRowCount()) and (self.currentColumn < self.getColumnCount()) ):
return self.env[self.currentRow][self.currentColumn]
else:
raise StopIteration
我遇到的问题是, iter 函数似乎将每行作为列表返回,但它没有调用下一个方法来进一步处理该列表。
我的目标是私下打印每个网格位置的值......如:
无 没有 ... 没有 0 没有 ... 无
有人可以详细说明我为什么缺少这个来实现这个目标吗?
答案 0 :(得分:2)
你可能会以太复杂的方式接近。
我会这样解决这个问题:
再举一个例子 - 你的移调是对称的,所以你看不出做错的效果。我们来看看
x = [[1, 2, 3, 4], [5, 6, 7, 8]]
现在。
使用zip()
或(对于大型列表)可能更好itertools.izip()
进行转置,并删除一个级别:
y = [j for i in itertools.izip(*x) for j in i]
在这里,izip()
遍历所有给定的列表,并将它们的第一个,第二个,...元素组合在一起以生成元组(1, 5), (2, 6)
,依此类推。 i
遍历这些元组,j
遍历其项目。因此y
为[1, 5, 2, 6, 3, 7, 4, 8]
。
现在,如果您希望您的类实例以这种方式进行迭代,您可以采用以下几种方法:
您可以__iter__()
成为生成器函数或返回迭代器,否则,e。克。
def __iter__(self): return (j for i in itertools.izip(*self.env) for j in i)
def __iter__(self):
for i in itertools.izip(*self.env):
for j in i: yield i
def __iter__(self): return iter([j for i in itertools.izip(*self.env) for j in i])
等。这样,您的对象是可迭代的,但不是迭代器。
您可以按照预期让对象成为自己的迭代器,让__iter__()
返回self
并实现next()
。但是,我会反对这一点
一旦用尽,您可以(并且应该)不重启此迭代器,因为您可以阅读here:
[...]一旦迭代器的next()方法引发StopIteration,它将继续在后续调用中这样做。不遵守此属性的实现被视为已损坏。 (这个约束是在Python 2.3中添加的;在Python 2.2中,根据此规则会破坏各种迭代器。)
因此,每次迭代都需要一个新对象。
您甚至可以使用__getitem__()
做有趣的事情,因为this是Python的“最后一次重写方法”,如果它不提供迭代器本身,则使对象可迭代,如由PEP234提出:
def __getitem__(self, index):
if index >= len(self): raise IndexError
# do a complicated calculation to map from this single index to your `self.env`
def __len__(self): # not needed, but handy
return sum(len(i) for i in self.env)
答案 1 :(得分:1)
您的__iter__
函数返回iter(self.env)
,它返回self.env的迭代器。如果您希望调用下一个方法__iter__
,则应返回self
。但是在您的实现中还存在其他问题,例如,您的迭代器将不会多次运行。
有更简单的方法来实现这一目标。您可以编写生成器表达式/列表理解来实现此目的(请参阅@ Eric的答案)。你也可以写一个generator method。 E.g:
def iter_column_row():
for i in range(self.getColumnCount()):
for j in range(self.getRowCount()):
yield self.env[j][i]
答案 2 :(得分:0)
def __iter__(self):
return (self.env[j][i] for i in range(columnCount)
for j in range(rowCount))
可能需要交换I和j