Select to view content in your preferred language

Concatenate iterating variable with string in For loop

6414
10
Jump to solution
11-23-2015 04:41 PM
EdwardGlover
Deactivated User

I summarize rows in a table in the SearchCursor and store them as variables.  I want to refer to these variables in the following update cursor to write to a table.  I get the following error on the second last line of code (in red): Tuple object does not support item assignment.  When I debug the code, ROW[0] equals 'ARSSPAN' as a string.  I want ROW[0] to reference the integer ARSSPAN summarized in the search cursor above.  In the next iteration of the UpdateCursor, I want the integer STSPAN to be written out, etc.  I feel my issue is with assembling a variable reference through concatenating a string with the iterator.  Any assistance would be greatly appreciated.

    # Create the search cursor to iterate through table and sum spans and cost

    with arcpy.da.SearchCursor(fcdtest, ("FeedClass","SHAPE_Length","MGMTCOST",)) as cursor:

        for row in cursor:

            if row[0] == "ARS":

                ARSSPAN += row[1]/55

                ARSCOST += row[2]

            elif row[0] == "ST":

                STSPAN += row[1]/55

                STCOST += row[2]

            elif row[0] == "S":

                SSPAN += row[1]/55

                SCOST += row[2]

            elif row[0] == "ARU":

                ARUSPAN += row[1]/55

                ARUCOST += row[2]

            elif row[0] == "UT":

                UTSPAN += row[1]/55

                UTCOST += row[2]

            elif row[0] == "U":

                USPAN += row[1]/55

                UCOST += row[2]

    fld = "YR2015"

    feedcls = ["ARS","ST","S","ARU","UT","U"]

    for cls in feedcls:

        with arcpy.da.UpdateCursor(out_data, (fld,)) as cursor:

            row[0] = cls + 'SPAN'

             cursor.updateRow(row)

0 Kudos
1 Solution

Accepted Solutions
ClintonDow1
Frequent Contributor

I see what you're doing here and it works, however I wouldn't recommend this approach as eval will run any python code, its a fairly large 'backdoor' so to speak (enables people to potentially inject malicious python code to run inside your code.. not so dangerous for a desktop script with known users, but could potentially compromise an entire organization if it was web based.)

Essentially eval is extracting the value from that concatenated string variable name by simply evaluating the variable name which returns the associated value, then assigning it to row[0].

Instead, I'd recommend instantiating a dictionary where the keys are your string keywords i.e.: "ARSSPAN" and the values are the associated int value. Then populate this dictionary in your SearchCursor loop, rather than simply assigning the variable names.

Then instead of using eval, you can use a string as the key in your dictionary - something like:

for cls in feedcls:

        with arcpy.da.UpdateCursor(out_data, (fld,)) as cursor:

            for row in cursor:

                row[0] = span_dict[cls + 'SPAN']

                print row[0]

                cursor.updateRow(row)

View solution in original post

10 Replies
ChristianWells
Esri Regular Contributor

Hi Edward,

It looks like this error may be due to line 28 still referencing the row object from the arcpy.da.SearchCursor(). I was able to reproduce the same behavior. However, if I change the script to the following, the issue goes away.

# Create the search cursor to iterate through table and sum spans and cost
with arcpy.da.SearchCursor(fcdtest, ("FeedClass","SHAPE_Length","MGMTCOST",)) as cursor:
    for row in cursor:
        if row[0] == "ARS":
            ARSSPAN += row[1]/55
            ARSCOST += row[2]
        elif row[0] == "ST":
            STSPAN += row[1]/55
            STCOST += row[2]
        elif row[0] == "S":
            SSPAN += row[1]/55
            SCOST += row[2]
        elif row[0] == "ARU":
            ARUSPAN += row[1]/55
            ARUCOST += row[2]
        elif row[0] == "UT":
            UTSPAN += row[1]/55
            UTCOST += row[2]
        elif row[0] == "U":
            USPAN += row[1]/55
            UCOST += row[2]

fld = "YR2015"
feedcls = ["ARS","ST","S","ARU","UT","U"]


for cls in feedcls:
    with arcpy.da.UpdateCursor(out_data, (fld,)) as cursor:
        for row in cursor:
            row[0] = cls + 'SPAN'
            cursor.updateRow(row)
EdwardGlover
Deactivated User

Hi Christian,

Thanks for correcting that error in my code.  Unfortunately, it hasn't resolved the issue with the UpdateCursor entirely.runtimegrab.jpg

0 Kudos
EdwardGlover
Deactivated User

To provide further context, the field I'm attempting to write to is a long integer type.  The variable list shows

ARSSPAN as an int; however, for row[0] it's listed as a string.  How do I make that string become the int variable I want to get the value from?  Even though in this case it's 0.

fldprops.jpg

variables.jpg

0 Kudos
DanPatterson_Retired
MVP Emeritus

ensure that there are no nulls in the field(s) before calculating on the field.  Are the results expected too be float, int or string?  This should be coded for or queried out before running

0 Kudos
EdwardGlover
Deactivated User

I've checked my sample dataset and there are values for shape_length in each row.  Both the span count (eg. ARSSPAN) and cost (eg. ARSCOST) are intended to be int variables.

0 Kudos
DanPatterson_Retired
MVP Emeritus

Edward, I was more worried about working with nulls in the other columns.  It is a topic of interest lately for some reason Before I forget ... # 18 ... Those pesky <null> things...

EdwardGlover
Deactivated User

Thank you for your insight.  I'm sure that post will alleviate forthcoming issues.  I'm really struggling with referencing a variable when the variable name is formed through concatenation.  I recall seeing many top quality posts from you when I worked in Avenue.  I'm a beginner programmer in Python and can't get over this hurdle. 

0 Kudos
EdwardGlover
Deactivated User

Converting a string to the variable name in Python use eval().

for cls in feedcls:

        with arcpy.da.UpdateCursor(out_data, (fld,)) as cursor:

            for row in cursor:

                row[0] = eval(cls + 'SPAN')

                print row[0]

                cursor.updateRow(row)

ClintonDow1
Frequent Contributor

I see what you're doing here and it works, however I wouldn't recommend this approach as eval will run any python code, its a fairly large 'backdoor' so to speak (enables people to potentially inject malicious python code to run inside your code.. not so dangerous for a desktop script with known users, but could potentially compromise an entire organization if it was web based.)

Essentially eval is extracting the value from that concatenated string variable name by simply evaluating the variable name which returns the associated value, then assigning it to row[0].

Instead, I'd recommend instantiating a dictionary where the keys are your string keywords i.e.: "ARSSPAN" and the values are the associated int value. Then populate this dictionary in your SearchCursor loop, rather than simply assigning the variable names.

Then instead of using eval, you can use a string as the key in your dictionary - something like:

for cls in feedcls:

        with arcpy.da.UpdateCursor(out_data, (fld,)) as cursor:

            for row in cursor:

                row[0] = span_dict[cls + 'SPAN']

                print row[0]

                cursor.updateRow(row)