On Mon, 09 Feb 2015 11:14:55 -0800, Charles Hixson wrote: > I'm trying to write a correct iteration over a doubly indexed container, > and what I've got so far is: def __next__ (self): > for row in range(self._rows): > for col in range(self._cols): > if self._grid[row][col]: > yield self._grid[row][col] > #end if > #end for col > #end for row raise StopIteration > > What bothers me is that it doesn't look like it would continue to raise > StopIteration if it were called again, which is what > https://docs.python.org/3/library/stdtypes.html#iterator.__next__ says > is correct. How should this be fixed?
You're mixing metaphors. You don't iterate over containers, you iterate over iterators that are returned to you by containers. So the container class itself has a __iter__ method, which returns a custom iterator object that has a __next__ method. Which is a lot of work. Or, you write your __iter__ like so: def __iter__ (self): for row in range(self._rows): for col in range(self._cols): if self._grid[row][col]: yield self._grid[row][col] In which case, Python's magic handling of yield handles the creation of the iterator object and the raising of StopIteration at the end of the __iter__ function all by itself. Or you write your __iter__ like so: def __iter__(self): return (self._grid[row][col] for col in range(self._cols) for row in range(self._rows) if self._grid[row][col] ) In which case you've returned a generator expression, which is a shorthand way of making an iterator. All extremely equivalent and a matter of personal taste (I'd probably opt for the yield one myself). -- Rob Gaddi, Highland Technology -- www.highlandtechnology.com Email address domain is currently out of order. See above to fix. -- https://mail.python.org/mailman/listinfo/python-list