__next__ and StopIteration
Rob Gaddi
rgaddi at technologyhighland.invalid
Mon Feb 9 14:27:04 EST 2015
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.
More information about the Python-list
mailing list