0

Are you able to update several fields within an attribute table at the same item within one Update Cursor command.

Code Example:

with arcpy.da.UpdateCursor (fc, fields) as cursor:
    for row in cursor:
       example2 = (row[0])
    if example == None:
        row[1] = None
        cursor.updateRow(row)
    else:
        variable = dict1[example2]
        row[1] = variable
        cursor.updateRow(row)
for row2 in cursor:
    example2 = (row1[0])
    if example2 == None:
        row1[1] = None
        cursor.updateRow(row)
    else:
        test = somedict[example2]
        row1[1] = test
        cursor.updateRow(row)
 del row

The above code executes but does not update the second column (the first one is updated properly).

The update cursor updates each column based on a dictionary I have created separately. Is this the best way to update a column's value in an attribute table based on a dictionary?

2 Answers 2

3

Your example code does not do what your post title asks. You are not attempting to update multiple columns (which are called fields) with a cursor. You are attempting to process through the cursor records (which are called features or rows) more than once with a single cursor. That is not allowed and is never really necessary, since there are better programming practices to follow.

The reason your code cannot work is that a cursor can only be used one time to iterate each record and after a cursor has moved past a given record that record cannot be accessed again by the cursor. So in your code, after the first for loop completes the cursor points to the end of the table and returns Nothing or None as the current record. So the second attempt to reuse the cursor using a second for loop is not allowed, since there is nothing to read or write to.

While PolyGeo's code will work, it is a bad habit to use multiple updateCursors on the same set of rows more than once in a program. His instructions at the end of his post concerning doing one pass of an update cursor are the best programming practice to follow. Multiple updateRow operations on a single row can cause issues and it is the most time consuming part of the update cursor operation. So good programming practice dictates that you only use updateRow once per feature per program.

The fields of a given row can be manipulated as much as you want prior to using the updateRow method, so you can write, read and rewrite to as many fields in a feature/row as you want as long as the cursor is still pointing to that feature/row prior to using the updateRow method. In other words, you are free to do multiple edits and reads of all the fields in a row if you need to on a single record, but only update the row once after you finish all edits and before moving to another record.

As long as you are not processing many millions of records that would exceed your available memory, if you need summary values from more than one feature/row, do not use an updateCursor to write the summary values as you are accumulating them from the features/rows. Instead, use a search cursor to read all the records and accumulate summary values into one or more dictionaries. The dictionary keys would be based on any fields that control the unique case value groupings for the summary values. After accumulating all summaries run an update cursor once and write the summary values from the dictionaries along with any updates you would normally do record by record. When all edits to a given record are complete you may use the updateRow method once per feature/row. This gives the best performance and is the most stable.

With appropriate conditional logic and a well structured program it is possible to handle all edits to all fields of any given record with a single update cursor and store all the edits you need to do to that record with a single call to the updateRow method.

In your example code row1 is never assigned a value. Normally an error would be thrown if you attempted to access the row1[0] value, but because the second for loop never processes since the cursor is empty that error never gets thrown. I suspect you did not mean to write "for row2 in cursor:" and meant to write "for row1 in cursor:" as you second for loop, but it does not matter since the second for loop will never run.

As best as I can tell here is what you meant to do and should be equivalent to what PolyGeo wrote, except that I test if the row[0] value actually exists in each dictionary first and if it does not exist in either dictionary then row[1] is set to None. If the row[0] value exists in both dictionaries, the value in somedict will take precedence over the value in dict1:

with arcpy.da.UpdateCursor (fc, fields) as cursor:
  for row in cursor:
    example = row[0]
    if example == None:
      row[1] = None
    else:
      variable = None
      if example in dict1:
        variable = dict1[example]
      if example in somedict:
        variable = somedict[example]
      row[1] = variable
    cursor.updateRow(row)
del row
1

It is hard to be certain what you are trying to do, and it should be fine to do all of this is a single pass of the update cursor.

However, I think you may be wanting to change data on the second pass based on changes made in the first pass so I have structured the code below to do that.

Perhaps give it a run and see how it goes.

with arcpy.da.UpdateCursor (fc, fields) as cursor:
    for row in cursor:
        example = (row[0])
        if example == None:
            row[1] = None
        else:
            variable = dict1[example]
            row[1] = variable
        cursor.updateRow(row)

with arcpy.da.UpdateCursor (fc, fields) as cursor:
    for row in cursor:
        example = (row[0])
        if example == None:
            row[1] = None
        else:
            test = somedict[example]
            row[1] = test
        cursor.updateRow(row)

If this works and you do want to do it all in one pass of the update cursor then the things to remember are:

  • using with means there is no need to have a del at the end because it cleans up the cursor and row objects itself
  • you only need to updateRow once at the end of each row iteration
1
  • 1
    I would try to structure it so that there's only one iteration, i.e. updating all fields in one pass of the cursor, but I can imagine situations (and have been in situations) where it is not possible to do everything in one pass. As long as the cursor is freed (either with or del) there's no problem in two iterations - it just takes twice as long to run. I like it, you've covered the basics and hit the heart of the problem in an economical amount of words. +1 from me. Commented Mar 30, 2015 at 1:22

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.