2

in the following function, what is making try: exit early? If I put the same code outside a def block it works fine.

tiles = ['095D', '094M']
in_file = 'in_file'
out_file = 'out_file'
expression = ''' "FIELDNAME" LIKE 'STUFF' '''

def foobar(in_file, out_file, expression):
    print in_file, out_file, expression
    try:
        print 'this is trying'
        #pretty print tile list, from http://stackoverflow.com/questions/2399112/python-print-delimited-list
        tiles = ','.join(map(str,tiles))
        print 'made it past tiles!'
        print 'From %s \nselecting %s \ninto %s' % (in_file, tiles, out_file)

    except:
        print 'Made it to the except block!'

foobar(in_file, out_file, expression)

Results:

D:\> python xx-debug.py
in_file out_file  "FIELDNAME" LIKE 'STUFF'
this is trying
Made it to the except block!

Results with the same code not in a def:

this is trying
made it past tiles!
From in_file
selecting 095D,094M
into out_file
Blixt
  • 49,547
  • 13
  • 120
  • 153
matt wilkie
  • 17,268
  • 24
  • 80
  • 115

3 Answers3

3

The reason it's not working is because you defined tiles in the global scope. In the function you're assigning to tiles. This makes tiles a local scoped name in the function. This, in turn, means that the code in the function won't look for tiles in the global scope at all.

In the assignment, you're trying to get tiles (this is before it has been assigned locally.) This results in an exception being raised, since you tried to access an unassigned local variable.

The quick fix is to use global:

...
def foobar(in_file, out_file, expression):
    global tiles
    ...

As others said, don't just catch exceptions without doing something with them. When debugging code, you want exceptions to be thrown so you can find and fix the cause! Either remove the try...except, or make the except take an exception and print useful information about it, like this:

try:
    ...
except Exception, e:
    print 'Oh noes!', e

This may be a lot to read, but you will understand Python much better if you do read it:

http://docs.python.org/reference/executionmodel.html

It explains how Python handles variable definitions in the module scope and function scopes, etc. It also covers exceptions.

Blixt
  • 49,547
  • 13
  • 120
  • 153
  • the real except block is `except:\n\tprint gp.GetMessages()\n` [(ref)](http://webhelp.esri.com/arcgiSDEsktop/9.3/body.cfm?tocVisable=1&ID=924&TopicName=Error%20handling%20with%20Python) I took it out when building the simplest possible reproduction of the error. Thanks for cluing me in to what was going on. – matt wilkie Nov 24 '10 at 06:12
3

Exception output:

Traceback (most recent call last):
  File "sof.py", line 19, in <module>
    foobar(in_file, out_file, expression)
  File "sof.py", line 11, in foobar
    tiles = ','.join(map(str,tiles))
UnboundLocalError: local variable 'tiles' referenced before assignment

Now, this happens because tiles is actually defined in the global space. So, your function should look like this:

def foobar(in_file, out_file, expression):
    global tiles
    ...
Mike
  • 1,060
  • 2
  • 11
  • 14
  • 2
    You should probably explain that it's happening because `tiles` is defined locally in the function, which means that any global variable will be ignored unless you use the `global` keyword. This error would happen even if you didn't define `tiles` globally. – Blixt Nov 24 '10 at 01:44
  • how did you get that UnboundLocalError message? All I get is silence. – matt wilkie Nov 24 '10 at 06:14
  • `except` swallows the exception. Without `except` you would get that error. – Blixt Nov 24 '10 at 17:17
-1

That's an interesting bug you have. So there's a module-scoped tiles outside the function, and since you're not using global, you're creating a new tiles variable inside the function. This is fine. Or it would be fine, except that it appears (when I mess around in interactive Python) that the lvalue of the statement (the tiles on the left) being local, makes the entire statement think that any reference to tiles means the local one. So in that map construct, instead of using the module tites it uses the local one, except the local one doesn't exist yet.

This may be a bug in Python, but probably it's as-intended.

jpsimons
  • 27,382
  • 3
  • 35
  • 45
  • 1
    Not a bug, it's very well-defined in fact. There's a difference between global and local variables. It's cases like these that you have the `global` keyword for. :) – Blixt Nov 24 '10 at 01:19
  • Right but you'd think it would evaluate the right side first using (as far as it knows at that point) global scope, then create a local variable and assign to that. It appears that Python scans ahead to see if a local variable by that name is ever created. – jpsimons Nov 24 '10 at 22:33