Using for-loops for cursors

When writing Python scripts to automate ArcGIS you often encounter all kind of cursors. Cursors are returned mostly returned by the gp object when calling functions like listtables, listfeatureclasses, listrasters, listfields, searchcursor, updatecursor, ... Usually cursors are used in the following way :
    import arcgisscripting
    gp = arcgisscripting.create()
    inputFC = r'path to a feature class'

    inRows = gp.searchcursor(inputFC)
    inRow = inRows.next()
    while inRow:
        ...do something
    inRow = inRows.next()
This is quiet a verbose way to loop through the rows. Fortunately there is a way to turn the cursor into an iterator that can be used in a for loop. This can be done by adding the following short class to your code.
    class CursorIterator(object):
        def __init__(self, cursor):
            self.cursor = cursor
            self.cursor.reset()
        def next(self):
            n = self.cursor.next()
            if n is None:
                self.cursor.reset()
                raise StopIteration
            return n
        def __iter__(self):
            return self
As it is nicely explained in Expert Python Programming by Tarek Ziadé we just created an iterator class. This is a container class with two methods namely next and __iter__. Usage of the CursorIterator class looks like this.
    rows = gp.searchcursor(inputFC)
    rowsIterator = CursorIterator(rows)
    for row in rowsIterator:
        ... do something
or shorter
    for row in CursorIterator(gp.searchcursor(inputFC)):
        ... do something
I hope you enjoyed my first post. Have fun.

Update : As Jason Schreider points out in his comment the CursorIterator class can be easily replaced by the following :
    rows = gp.searchcursor(inputFC)
    for row in iter(rows.next, None):
        ... do something

8 comments:

Rich said...

I am looking for assistance in either your script or another that I have that creates polygons from the extents of rasters. What we have are subfolders of imagery. All of which are captured in a unmanaged raster catalog which I would like to use to build a cache from on my GIS Server. How do you get the listrasters to do a recursive drill down into subfolders (upwards of 60 subfolders)? Other recommendations are welcome.

travlerfx@gmail.com

Samuel said...

Hello,

What you can do is use the os.walk function.

for root, directories, files in os.walk(startdir):
gp.workspace = root
...

Succes

Jason Scheirer said...

Or easier, using Python's second iter() behavior:

for row in iter(cursor.next, None):
...

Samuel said...

Thanks for the tip !!! I must have overlooked this. Still got a lot to learn.

sephi said...

Does it make it faster?
I'm running a search cursor on a 300000 features in a FC.
the searchRow = search.Next() every iteration takes a long time...

Samuel said...

It will not make it faster because it calls the search.Next() under the hood. It only makes it more convenient to use in Python.

Anonymous said...

So how do I decide which to use when writing a Python script - For Loop or a While Loop?

There doesn't seem to be any discussion on when to use what and the "help" doesn't address this at all.

see> http://resources.arcgis.com/en/help/main/10.1/index.html#/UpdateCursor/018v00000064000000/

Samuel Bosch said...

I would use a for loop for any new code that you write because the for loop is more compact to write and you can't forget to update the row (row = cursor.next()) and in that way create an infinite while loop.