Take the 2-minute tour ×
Geographic Information Systems Stack Exchange is a question and answer site for cartographers, geographers and GIS professionals. It's 100% free, no registration required.

I need to use CalculateField_management in a Python script, and the calc expression needs to concatenate a runtime variable, a string, and a field (string) value. I have searched all over for examples from which to learn. I have tried many things I have found in my research and some of my own ideas, too, but I just can't get the calc expression to evaluate. I am now completely confused and need some help to dig out of this hole. So, here's the scoop.

The field to be calculated, DESCRIP, is a string field in a fGDB feature class with one feature. The runtime variable, enddesg, will be a string. Essentially, what I want to do is concatenate the runtime value with a (longish) string and prepend that to the existing value in the DESCRIP field, storing the result back in the DESCRIP field. I have tried many forms of an "all-in-one" string for the expression, but nothing worked. I came to the conclusion that a pre-logic approach would be better, but I haven't been able to get that to work either. Below is what I have right now.

expr = "getDescription(str(enddesg))"
codeblock = """def getDescription(endstr):
    exprstr = endstr + ' Touchdown Zone Elevation;duplicated from existing control point;' + !DESCRIP!
    return exprstr"""
arcpy.CalculateField_management(perpptsSX_src, "DESCRIP", expr, 'PYTHON_9.3', codeblock)  #Should be only one feature in the source

(BTW, the enddesg variable is either a string or an integer but is converted to a string as input.) I get the following error:

<class 'arcgisscripting.ExecuteError'>: Failed to execute. Parameters are not valid.
ERROR 000989: Python syntax error: Parsing error <type 'exceptions.SyntaxError'>: invalid syntax (line 2)

Failed to execute (CalculateField).

The following code variation produces no errors, but I also get nothing entered in the DESCRIP field.

expr = "getDescription(str(enddesg), !DESCRIP!)"
codeblock = """def getDescription(endstr, desc):
    exprstr = endstr + ' Touchdown Zone Elevation;duplicated from existing control point;' + desc
    return exprstr"""

So, I am now thoroughly confused. I work at home and do not have access to another fresh pair of experienced eyes to look at my code. If anyone can help me out, I would much appreciate it. -- Ti

share|improve this question
add comment

3 Answers 3

up vote 8 down vote accepted

I never understand why people even try to mess with CalculateField_management within a Python script instead of just doing their updates within an UpdateCursor.

Not only do you not have to worry about escaping characters and writing Python functions within Python strings (shudder), you can update multiple fields at once.

It's very easy with the newer arcpy cursor iteration syntax:

rows = arcpy.UpdateCursor(fc)
for row in rows:
    row.DESCRIP = "%s Touchdown Zone Elevation;duplicated from existing control point;%s" % (str(enddesg), row.DESCRIP)
    rows.updateRow(row)
del rows

The magic on the row.DESCRIP = line is called string formatting in Python -- in this case it wasn't that necessary but when you're concatenating more than a couple of strings or need some specific numeric formatting it's really handy.

The other thing to note is that instead of hardcoding the field name (row.DESCRIP) you can also get and set field values using a variable to specify the field using row.getValue and row.setValue instead.

For the most part, I would suggest using getValue and setValue as it makes your code much easier to maintain if the field name changes or you want to write a generic function or script tool with the field name(s) as parameters.

share|improve this answer
    
Thank you for this. I usually avoid Update Cursors, because performance can be so abysmal on large datasets. I am normally working with very large datasets, and it just didn't click with me that, in this case, speed just isn't an issue. The update cursor method worked fine, of course, and I shall move on. Just for my own edification, though, I really would like to find out the solution to using CalculateField. I do work with complex legacy scripts that need updating now and again. The knowledge would be helpful. Thanks, again, all. –  celticflute Jul 27 '11 at 13:38
    
Cursors are slow and smelly. :( And besides, you can use string substitution just as easily in a codeblock, can you not? –  Nathanus Jul 27 '11 at 16:07
    
@Nathanus, I've never noticed any performance issues with UpdateCursors but in 10.1 they are supposed to be faster. I would be interested in seeing if anyone has timed the two with varying size tables. And sure you can do string substitution in a function written in the code block of CalculateValue, but I find doing so is less maintainable and readable and just all around a PITA compared to doing it with a cursor. You would need to do CalculateValue once for each field which is surely going to be slower than an cursor that updates multiple fields at once. –  blah238 Jul 27 '11 at 16:43
    
correction CalculateField where I said CalculateValue -- darn 5 minute edit limit! –  blah238 Jul 27 '11 at 16:49
    
This looks indeed likes a much cleaner then using calculateField in python. Due to the claims of the abysmal performance on large datasets I decided to test it myself. –  tmske Nov 10 '11 at 9:34
show 2 more comments

I might be wrong, but I believe you are not supposed to put the field name !DESCRIP! in the code block. Use a placeholder variable and it should function properly.

share|improve this answer
    
Yup. !field! only works in the expression. –  Jason Scheirer Jul 26 '11 at 20:54
add comment

In my testing, calling str() on an argument in your expression causes the tool to fail. Maybe try:

expr = "getDescription(enddesg, !DESCRIP!)"
codeblock = """def getDescription(endstr, desc):
    exprstr = str(endstr) + ' Touchdown Zone Elevation;duplicated from existing control point;' + desc
    return exprstr"""
share|improve this answer
    
Why not convert it to a string inside the codeblock so that it can concatenate happily? –  Nathanus Jul 26 '11 at 21:18
    
@Nathanus that should work :-), I'm going to edit my answer. –  Derek Swingley Jul 26 '11 at 21:23
    
@Derek Swingley - I thought it would work, too ... until it didn't. Same result. No errors, just nothing entered into the DESCRIP field. I did try converting the enddesg variable to a string before the expression statement and just passing in the string: no converting in either the expression statement or the codeblock. Still the same result. Hmmm. I shall continue to pound on this, but I would appreciate any further thoughts any of you may have. –  celticflute Jul 27 '11 at 2:10
    
UPDATE - I tried the above code in the Field Calculator (with the variation of getDescription('10', !DESCRIP!) for testing on a single feature), and it worked just fine. So, the logic is fine, but there is something funky about how the code is passed to and interpreted in the CalculateField_management tool. I think it must have something to do with how things are quoted. Any thoughts? –  celticflute Jul 27 '11 at 2:52
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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