Update cursor not replacing values in python script

3076
7
Jump to solution
05-25-2017 12:05 PM
JoshuaBrengel
New Contributor III

Hello, I am trying to use an update cursor on an attribute table of a feature class (called Lancowatersheds) in order to replace certain characters in values in a specific field of the table (called STORMWATER).  I tried the following code and when I used the print function to show desired changes (remove all "-" and "\" from all values in the STORMWATER field and replace with " "), the update cursor did not seem to work (values still had those funky characters in them):

# Import arcpy
import arcpy

# Set environments
from arcpy import env
env.workspace = "C:/GIS_Data/Test"
arcpy.env.overwriteOutput = True

# Input feature class
in_fc = "C:/GIS_Data/Test/TEST/Lancowatersheds.shp" 

with arcpy.da.UpdateCursor(in_fc, ["STORMWATER"]) as cursor:
    for row in cursor:
        row[0].replace("-", " ")
        row[0].replace("\\", " ")
        cursor.updateRow(row)
        print row
    del row
    del cursor

Here's a list of all the original values in the STORMWATER field:

 ['SUSQUEHANNA RIVER', 'PEQUEA CREEK', 'OCTORARO CREEK', 'MILL CREEK', 'LITTLE CONESTOGA CREEK', 'CONOWINGO CREEK', 'CONEWAGO CREEK-DAUPHIN', 'CONESTOGA RIVER', 'COCALICO CREEK', 'CHICKIES CREEK', 'DONEGAL\LOWER CHICKIES CREEK']

I then put all the desired values from the "STORMWATER" field into a list (e.g. there should be no weird characters in the values because I ran the update cursor).  I wanted to use this list to select certain features from the original shapefile "Lancowatersheds" and make that selection a standalone feature class.  Here's that code:

wsheds = ['SUSQUEHANNA RIVER', 'PEQUEA CREEK', 'OCTORARO CREEK', 'MILL CREEK', 'LITTLE CONESTOGA CREEK', 
        'CONOWINGO CREEK', 'CONEWAGO CREEK DAUPHIN', 'CONESTOGA RIVER', 'COCALICO CREEK', 'CHICKIES CREEK', 'DONEGAL LOWER CHICKIES CREEK']

for shed in wsheds:
    arcpy.MakeFeatureLayer_management(in_fc, "lyr")
    whereExp = "\"STORMWATER\" = \'{0}\'".format(shed)
    arcpy.SelectLayerByAttribute_management("lyr", "NEW_SELECTION", whereExp)
    arcpy.CopyFeatures_management("lyr", '{0:s}'.format(shed))
‍‍‍‍‍‍‍‍

  

I got the above code to work for all the objects in the my "wsheds" list whose original values did not contain a "-" or "\" , but for the two objects in the STORMWATER field whose original values contained those characters, no such luck.  Maybe automating is a bit much for such a small data set, but I guess my ultimate goal is to understand how to use update cursors to replace any character in a value in any field of an attribute table.  I could see this being a useful skill when dealing with much larger data sets. Thanks!!

0 Kudos
1 Solution

Accepted Solutions
IanMurray
Frequent Contributor

Python strings are immutable, you cannot simply just change the value in your existing row using the replace method on the existing string.  You would need to set row[0] to a new string that replaces the values in the old string.

row[0] = row[0].replace("-", " ")

https://www.tutorialspoint.com/python/string_replace.htm

Also, when using a with statement, you do not need to delete your cursor it will close upon completion.

View solution in original post

7 Replies
IanMurray
Frequent Contributor

Python strings are immutable, you cannot simply just change the value in your existing row using the replace method on the existing string.  You would need to set row[0] to a new string that replaces the values in the old string.

row[0] = row[0].replace("-", " ")

https://www.tutorialspoint.com/python/string_replace.htm

Also, when using a with statement, you do not need to delete your cursor it will close upon completion.

JoshuaBrengel
New Contributor III

Thanks Ian! I will have to try this.  I'm still a bit confused as to how exactly assigning row[0].replace to row[0] gets around the problem of immutability, but I get the fact that strings are immutable and the replace() method won't work on the strings directly.  Unfortunately, I forgot to load my data to my personal laptop and won't be able to try this fix for a few days... Thanks again!

0 Kudos
JoshuaBixby
MVP Esteemed Contributor

Since replace is a Python method and not an ArcPy method, it is good to check the Python documentation:  Python String Methods.

str.replace(old, new[, count])

Return a copy of the string with all occurrences of substring old replaced by new. If the optional argument count is given, only the first count occurrences are replaced.

Regardless of the mutability or immutability of Python strings, the replace method returns "a copy of the string ...."  The reason replace returns a copy is because Python strings are immutable, as Ian Murray‌ points out.  Your original code is generating a copy of the string with the changes you want, but you aren't doing anything with the new string, like reassigning it back to row[0].

JoshuaBrengel
New Contributor III

Thanks for the further explanation! The reason why I have to assign row[0] to the row[0].replace object makes complete sense now. Thanks!

0 Kudos
JoshuaBixby
MVP Esteemed Contributor

If the cursor encounters an error, using the with statement allows for the connections to be cleaned up.  If the cursor doesn't run into an error, then using the with statement resets the cursor so it can be iterated over again without using cursor.reset().  To remove all of the locks, including schema locks, the cursor still needs to be deleted. 

MitchHolley1
MVP Regular Contributor

You could use Calculate Field—Help | ArcGIS for Desktop for this.

Something like this:

arcpy.CalculateField_management(in_fc, "STORMWATER", """str(!STORMWATER!).replace("-","")""", "PYTHON_9.3", "")
JoshuaBrengel
New Contributor III

I guess I didn't even think about using CalculateField_management. Seems like a good route (though I suppose it has its positives and negatives just like cursors) and will have to keep it in mind.  In this case, I'm hoping to use cursors, but never hurts to think about something from another angle! Thanks!

0 Kudos