Python __iter__和next()函数

时间:2012-10-18 06:25:48

标签: python

在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 没有 ... 无

有人可以详细说明我为什么缺少这个来实现这个目标吗?

3 个答案:

答案 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