Named tuples from Python collections with arcpy

I am reading a book by Jeff Knupp Writing Idiomatic Python and thought to share a great tip for everyone who works with arcpy and Python.

If you are scripting in ArcGIS, you have probably done it a hundred times. Set up a workspace, create a cursor object for a feature class or a table and then retrieve the rows.

Rows are represented as a list of tuples:

rows = [(57525, 57526, 179.4063375296146),
(57525, 57529, 107.75624872381789),
(57525, 57530, 73.06809412350371),
(57526, 57529, 71.6500888057982)]

Then if you need to access individual attributes of a feature, you would use an index value starting from zero:

for row in rows:
print row[0]

It’s OK with just a few columns but what if your business logic involves having dozens of columns and you need to access them individually? You would end up having lots of row[14] and row[23]. Then you would either comment the row with the clarification on what field this index value actually represents, count manually to see what column you are actually accessing or create a variable for each value with the name replicating the column name or alias.

In either case you would end up having a bunch of the code that is hard to maintain and read. This is where named tuples come into play. I wish I’ve learned about them earlier.

The rows I added earlier represents the source and destination features ID (polylines) and the angle at which they intersect. It would be so much easier to read the code if we could use column names instead of indexes.

from collections import namedtuple
featureRow = namedtuple("featureRow",['sourceId','destId','angle'])
for row in rows:
feature = featureRow._make(row)
print feature

>>> featureRow(sourceId=57525, destId=57526, angle=179.4063375296146)

You could also access the feature attributes by accessing the attributes of the feature object:

row_info_string = 'Angle from feature {sourceId} to feature {destId} is {angle}'
print(row_info_string.format(sourceId=feature.sourceId, destId=feature.destId,angle=feature.angle))

If you have many fields, then instead of retyping them or coming up with alternative names, you could just get a list of the fields in the table.

fields = [ for field in arcpy.ListFields(feature_class)]
featureRow = namedtuple("featureRow",fields)
print feature

>>> featureRow(SourceID=57525, DestinationID=57526, Angle=179.4063375296146)

Print feature.SourceID

>>> 57525

Using the named tuple with the notation is so much easier and nicer to read. Try it and you will love it!


3 thoughts on “Named tuples from Python collections with arcpy

  1. It’s in reality a great and helpful piece of info. I’m glad that you
    simply shared this helpful information with us.
    Please keep us up to date like this. Thank you for sharing.

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s