Python GIS features

How do you access the attributes and geometry of features in your favorite Python and GIS environment? Let's imagine we're interested in the state_name attribute from a US States data set and compare. I'll employ the iterable adapters I introduced in a previous post to simplify the code.

ESRI:

for row in ESRICollection(rows):
    state_name = row.state_name
    geom = row.shape

That's not bad at all, although there's potential for name collisions.

FME:

for f in FMECollection(features):
    state_name = f.getAttribute('state_name')
    geom_type = f.getGeometryType()
    geom_coords = f.getCoordinates()

Evil or not, getters and setters aren't needed in Python.

OGR (earlier than 1.5):

for f in OGRCollection(layer):
    state_name = f.GetFieldAsString('state_name')
    geom = f.GetGeometryRef()

    # Don't forget to free the memory allocated for the feature!
    f.Destroy()

Destroy!

OGR (current, also known as osgeo.ogr):

for f in layer:
    state_name = f.state_name
    geom = f.geometry()

Howard Butler has made osgeo.ogr much more peaceful.

QGIS:

for f in QGISCollection(provider):
    attribs = f.attributeMap()
    state_name = attribs['state_name'].toString()
    geom = f.geometry()

A mapping of attributes is design that I like, but it could be more user friendly.

5 different environments, 5 different ways.

Ideally, feature attributes (not to be confused with Python object attributes) are accessed through a mapping attribute to prevent collisions in the feature's own namespace, and the feature geometry is simply another attribute:

for f in features:
    # A dict has all kinds of nice built-in features, like
    attribute_items = f.properties.items() # [('state_name', 'Utah'), ...]
    assert 'state_name' in f.properties # True

    state_name = f.properties['state_name']
    geom = f.geometry

Looks a bit like GeoJSON? Yes, it does.