ArcPy – When to Update Row Within Update Cursor with Multiple If Statements

arcpycursorif else

I have a model that requires a stupid number of conditional statements. The older version was utilizing feature layers, select by attributes, and Calculate fields many, many times. I rewrote it to utilize a mass of nested if, elif, and else statements as well as a dictionary made from a search cursor from another feature class.

My problem is that I'm not quite sure where to place updateRow(row) statements so that the data is properly updated. The cursor updates a lot of different fields. Most of them are simple updates, but almost all still depend on various conditional statements. This question is for a single simple segment before the messiest parts.

I tried to simplify it as much as possible to show. I assign the age field within the cursor but also need to reference that same field (after its been assigned) to perform calculations. Do I need to update the row after each age or would the cursor.updateRow(row) line be placed after the age assignment and then a gain after the AgeMult assignments?

with arcpy.da.UpdateCursor(ci_masterpoints, flds) as cursor:
    # start looking at rows
    for row in cursor:
        row[flds.index('TodaysDate')] = datetime.datetime.now().strftime('%d/%m/%Y')
        row[flds.index('TodaysDateYr')] = datetime.datetime.now().year
        age = row[flds.index('Age')]
        # If the work order number matches to a wonum in conditions...
        if mx_row in conditions:
            row[flds.index('Leak_Location')] = conditions[mx_row]
        # Avoid null values but assign year based on Actual_Finish
        if row[flds.index('Actual_Finish')] != None:
            # Assign the year to DateInstallYr
            row[flds.index('DateInstallYr')] = row[flds.index('Actual_Finish')].year
            age = row[flds.index('TodaysDateYr')] - row[flds.index('DateInstallYr')]
        if age == None:
            row[flds.index('AgeMult')] = 1
        elif age > 10 and age < 20:
             row[flds.index('AgeMult')] = 0.9
        elif age > 20:
            row[flds.index('AgeMult')] = 0.75

Best Answer

Run your cursor.updateRow(row) just once per row that includes any changes and run it after all changes for that row. Since you change values for every row (at least for the dates), then you need to run it once for each row, after all changes for the row.

Therefore run it as the last line in the for loop, outside of any if clauses. Ie, Use only one cursor.updateRow(row) statement.

The cursor.updateRow(row) writes all values for that row at once, so there's no point running it for each value. Run it once only for the entire row.

Eg:

with arcpy.da.UpdateCursor(ci_masterpoints, flds) as cursor:
    # start looking at rows
    for row in cursor:
        row[flds.index('TodaysDate')] = datetime.datetime.now().strftime('%d/%m/%Y')
        row[flds.index('TodaysDateYr')] = datetime.datetime.now().year
        age = row[flds.index('Age')]
        # If the work order number matches to a wonum in conditions...
        if mx_row in conditions:
            row[flds.index('Leak_Location')] = conditions[mx_row]
        # Avoid null values but assign year based on Actual_Finish
        if row[flds.index('Actual_Finish')] != None:
            # Assign the year to DateInstallYr
            row[flds.index('DateInstallYr')] = row[flds.index('Actual_Finish')].year
            age = row[flds.index('TodaysDateYr')] - row[flds.index('DateInstallYr')]
        if age == None:
            row[flds.index('AgeMult')] = 1
        elif age > 10 and age < 20:
             row[flds.index('AgeMult')] = 0.9
        elif age > 20:
            row[flds.index('AgeMult')] = 0.75
        cursor.updateRow(row)
Related Question