Select to view content in your preferred language

Python variable not defined

6210
10
Jump to solution
07-01-2015 10:14 AM
CoyPotts1
Occasional Contributor III

I keep getting an error that says that my variable (region) is not defined.  Please see the code below:

# Set local variables
mapName = str(mxd.filePath).split('\\')[-1:][0][:-4]
region = mapName[:2]
inTable = nodeFeatures
inField = "CUSTRegion"
expression = "Reclass (!CUSTNodeID!, !CUSTRegion!)"
codeBlock = """def Reclass (CUSTNodeID, CUSTRegion):
    if CUSTNodeID != None:
        return region
    else:
        return None"""

# Execute CalculateField
arcpy.CalculateField_management(inTable, inField, expression, "PYTHON_9.3", codeBlock)

The variable "mapName" grabs the name of the map and turns it into a string.  The map name has 4 parts REGION - STATE - PROJECT - CUSTOMER.  The variable "region" takes the mapName variable and grabs the first two characters, which is the abbreviated region code ("NC", "NE", etc...)

I originally had these two variables at the top of the script just under where I import the modules, but I thought that I would move them down closer to the process that uses them hoping it would help (I'm still pretty green with Python so I'm not even sure if it matters where the variable is located).  I put it at the top to begin with because there are A LOT of process in the whole script that use the same variables.

I can run this script in the Python window just fine, but when I create a python tool in a toolbox, I keep getting the error that says that the variable "region" is not defined.  I've tried it with replacing "region" with "mapName[:2]" and that just returns saying that "mapName" is undefined.  I tried using "str(region)" and "str(mapName[:2])" to no avail.

Do I need to move the variables somewhere or change some sort of defining operator or something?

0 Kudos
1 Solution

Accepted Solutions
DarrenWiens2
MVP Honored Contributor

Ah, I just tested this and it should work (a few more quotes needed):

codeBlock = """def Reclass (CUSTNodeID, CUSTRegion):  
    if CUSTNodeID != None:  
        return ' """ + region + """ ' # you can remove the space between single and triple quotes
    else:  
        return None""" 

View solution in original post

10 Replies
DarrenWiens2
MVP Honored Contributor

Disclaimer: not exactly sure I'll describe this right, but here's how I imagine it happening.

Your script executes through Python one line at a time. Line 1 is a comment, Line 2 assigns some value to a variable named mapName, etc. Line 7 assigns a string to a variable named codeBlock. It does not execute the code within that string. I repeat, this is just a string.

Line 14 is where all the previous lines come together. Everything is packaged up and sent, somewhat blindly, to a new Python interpreter (not totally sure how to explain this). Everything in codeBlock is sent together. No substitution happened in the codeBlock string. This new Python instance does have the scope to access your main script. It is a separate thing. Once it's done it's thing, it will disappear and return to your original script.

In the end, you should be able to solve your problem by substituting the value of the region variable into the codeBlock variable before sending it to CalculateField. Something like:

codeBlock = """def Reclass (CUSTNodeID, CUSTRegion): 
    if CUSTNodeID != None: 
        return " + region + "
    else: 
        return None""" 
CoyPotts1
Occasional Contributor III

From what I can understand of your example, which may very well be incorrect, is that the result would fill the desired field with the literal text string of " + region + ", instead of the two digit region abbreviation that the mapName[:2] gives me. 

In the example I pasted in my original posting, if I use 'region' or "region" instead of just region, then it runs through just fine and updates my field with the literal string that I quoted, and not the value given to region earlier in the script.

0 Kudos
JoshuaBixby
MVP Esteemed Contributor

The first thing that comes to mind is scope and namespace issues, not syntax, per se.  Do you have background processing under Geoprocessing options enabled or disabled?  If disabled, does your code run if you enable it?

Are you running a Python script in a regular Toolbox or a Python Toolbox?

0 Kudos
CoyPotts1
Occasional Contributor III

I have background GP disabled.  I leave it like that because there are parts of my script that export a table to an Excel sheet, and the tools for Excel functionality are not compatible with 64bit processing.  Details on that are here.

I added a script tool to a normal toolbox that references the .py document.

0 Kudos
DarrenWiens2
MVP Honored Contributor

I believe my example should return the two-letter value stored in the variable region, by escaping it outside the static codeBlock string. At least, that was my intention.

The codeBlock string starts with triple quotes, which I take to mean: " (start the string) + "" (insert literal quote here). By surrounding the variable result with single quotes you are saying: " (end the string) + result variable value + " (start the string again)

edit: as Joshua Bixby​ points out below, this is clearly an incorrect explanation.

0 Kudos
CoyPotts1
Occasional Contributor III

Whenever I tried it exactly as you have it typed in your example, I get the following error.

0 Kudos
DarrenWiens2
MVP Honored Contributor

Ah, I just tested this and it should work (a few more quotes needed):

codeBlock = """def Reclass (CUSTNodeID, CUSTRegion):  
    if CUSTNodeID != None:  
        return ' """ + region + """ ' # you can remove the space between single and triple quotes
    else:  
        return None""" 

CoyPotts1
Occasional Contributor III

Great!  That works like a charm.

Now moving on to why?  What does the triple double quotes do?  I'm assuming the single quotes make it a string, correct?

Thanks for figuring that out for me,

0 Kudos
JoshuaBixby
MVP Esteemed Contributor

From the Python documentation on String Literals:

In triple-quoted strings, unescaped newlines and quotes are allowed (and are retained), except that three unescaped quotes in a row terminate the string. (A “quote” is the character used to open the string, i.e. either ' or ".)

Since unescaped newlines and quotes are allowed in triple-quoted strings, you need to terminate the triple-quoted string before trying to concatenate it with another string using "normal" syntax.