I have a simple arcpy script to update a field in a point shapefile with info from the polygon feature that it is within. It takes 9 minutes to do 100 points in arcpy but a spatial join in arcmap is instantaneous. I'm sure there is a quick established way to solve this problem. Can someone point me in the right direction?

import took 0:00:07.085000
extent took 0:00:05.991000
one pt loop took 0:00:03.780000
one pt loop took 0:00:03.850000
one pt loop took 0:00:03.791000

import datetime
t1 = datetime.datetime.now()
import arcpy
t2 = datetime.datetime.now()
print "import took %s" %  ( t2-t1)
#set up environment
arcpy.env.workspace = "data\\"
arcpy.env.overwriteOutput = True

desc = arcpy.Describe("parcels.shp")
ext = desc.Extent
extent = (ext.XMin,ext.XMax,ext.YMin,ext.YMax)
t3 = datetime.datetime.now()
print "extent took %s" %  (t3 -t2)
fc = arcpy.CreateRandomPoints_management("", "malls.shp", "", ext, 100, "", "POINT", "")
arcpy.AddField_management("malls.shp", 'ParcelID', 'LONG')

rows = arcpy.UpdateCursor('malls.shp',"","",'ParcelID')
for row in rows:
    t4 = datetime.datetime.now()
    pt = row.Shape.getPart()
    for polyrow in arcpy.SearchCursor('parcels.shp'):
        t6 = datetime.datetime.now()
        poly = polyrow.getValue('Shape')
        if extent[0]<pt.X<extent[1] and extent[2]<pt.Y<extent[3]:
            if poly.contains(pt):
                print "works"
                row.ParcelID = polyrow.Parcels_ID
                break #we can stop looking for matches since
        t7 = datetime.datetime.now()
        "a full poly loop took %s" % (t7-t6)
    t5 = datetime.datetime.now()
    print "one pt loop took %s" % (t5-t4)

print datetime.datetime.now() -t1
  • 4
    Which version of ArcGIS are you at? 10.1 added the arcpy.da (Data Access) module with (much) faster versions of the cursors.
    – blah238
    Mar 9, 2013 at 23:09

2 Answers 2


If you need to create a second cursor for parcels.shp, do so outside of the loop for your first cursor. As it stands, your script is creating a new cursor object for each row in malls.shp which is what's costing you all that processing time.

rows = arcpy.UpdateCursor('malls.shp',"","",'ParcelID')
polyrows = arcpy.SearchCursor('parcels.shp')
for row in rows:
    t4 = datetime.datetime.now()
    pt = row.Shape.getPart()
    for polyrow in polyrows:
  • This was exactly it. Thank you. and then I use .reset() on my second cursor for each time i want to traverse it? It seems like it only goes through the cursor 1 time now.
    – EmdyP
    Mar 9, 2013 at 21:33
  • Hmm, you shouldn't need to reset the rows. Make sure you are deleting both row objects and cursor objects at the end of the script. Funny things can happen if you don't. Mar 9, 2013 at 21:57
  • I think the inner loop's cursor does need to be reset each time if you go this route. See my answer for an alternative.
    – blah238
    Mar 9, 2013 at 23:45

The problem with @Jason's answer (and your original approach) is that it does not take advantage of the spatial index and requires a nested, two-cursor loop which is going to become exponentially slower as the number of points increases.

An alternative workflow that may be faster while still letting you update the point feature class in-place (Spatial Join only outputs a new feature class, not updates an existing one) might be to:

  1. Use Spatial Join to create an intermediate (perhaps in-memory) feature class
  2. Use Add Join to join the intermediate feature class to your existing point feature class
  3. Use Calculate Field or an UpdateCursor to copy over the values in the joined field to the field in the existing point feature class.
  • 2
    I like this alternative workflow - I love that even though I didn't ask the question I'm still learning new ways to do things here. Mar 12, 2013 at 13:44

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.