Iterators, again

If your favorite Python GIS environment doesn't provide iterators, you can easily implement adapters like these.

ESRI (ArcGIS 9.3):

class ESRICollection(object):

    def __init__(self, context):
        self.context = context

    def __iter__(self):
        row = self.context.next()
        while row:
            yield row
            row = self.context.next()
        raise StopIteration

More or less as done here. Usage:

>>> for f in ESRICollection(rows):
...     # work with f

QGIS:

class QGISCollection(object):

    def __init__(self, context):
        self.context = context

    def __iter__(self):
        feat = QgsFeature()
        while provider.getNextFeature(feat):
            yield feat
            feat = QgsFeature()
        raise StopIteration

Returning new objects from the iterator rather than returning the same object with new values heads off unpleasant surprises. Usage:

>>> for f in QGISCollection(provider):
...     # work with f

OGR (earlier than 1.5):

class OGRCollection(object):

    def __init__(self, context):
        self.context = context

    def __iter__(self):
      feature = layer.GetNextFeature()
      while feature:
          yield feature
          feature = layer.GetNextFeature()
      raise StopIteration

Usage:

>>> for f in OGRCollection(layer):
...     # work with f

Notice a big difference between yield and return: the former gives a value, but execution continues after the statement rather than breaking as with the latter.

Comments

Re: Iterators, again

Author: Eric Wolf

Thanks Sean! I've been wondering how to overload iteration in Python. Haven't bothered to find out on my own. Should make stupid ESRI cursor code a little cleaner.