Weird import behavior

T

Tommytrojan

Hi,

I have been using Python for a while but today I came across a really
strange behavior:

While poking around in Queue.py due to problems with importing this
module from a thread I got an error that a module that I imported on
top of the file could not be accessed. I reduced the problem to this
small script:

import string
import os

class T:
def __init__(self):
try:
print 'xxx nothing to do'
except ImportError:
print 'got an import error'
import os as string

print 'xxxx string module', string

t=T()


The import clause in the except statement (although never executed)
removes the reference to the string module imported at the beginning of
the script. Any idea why this is the case?

Thanks,
Tommy
 
D

Duncan Booth

Tommytrojan said:
import string
import os

class T:
def __init__(self):
try:
print 'xxx nothing to do'
except ImportError:
print 'got an import error'
import os as string

print 'xxxx string module', string

t=T()


The import clause in the except statement (although never executed)
removes the reference to the string module imported at the beginning of
the script. Any idea why this is the case?

Quoting the error message would have made the answer instantly clear to
everyone, including probably yourself:

UnboundLocalError: local variable 'string' referenced before assignment

Assigning to the variable 'string' anywhere in the function makes it a
local variable throughout the function. Use 'global string' if you want the
import to affect the global variable.
 
T

Tommytrojan

Duncan,

thanks for your quick reply. I guess I should have included the output.
I thought I was clear in the error description.
The problem is that I never assign to 'string'. I only reference it (as
the error message correctly states). If you comment out the import
statement in the except clause the program runs fine. Now notice that
the exception hander never gets executed! Any explanation?
 
D

Duncan Booth

Tommytrojan said:
Duncan,

thanks for your quick reply. I guess I should have included the output.
I thought I was clear in the error description.
The problem is that I never assign to 'string'. I only reference it (as
the error message correctly states). If you comment out the import
statement in the except clause the program runs fine. Now notice that
the exception hander never gets executed! Any explanation?
You have an assignment to 'string' in the function (import, class and def
statements are all equivalent to assignment statements so far as scoping
is concerned). It doesn't matter whether or not the assignment gets
executed: the compiler flags the variable as a local variable.

See the Python FAQ, 1.2.2:

1.2.2 What are the rules for local and global variables in Python?

In Python, variables that are only referenced inside a function are
implicitly global. If a variable is assigned a new value anywhere within
the function's body, it's assumed to be a local. If a variable is ever
assigned a new value inside the function, the variable is implicitly local,
and you need to explicitly declare it as 'global'.
 
F

Fredrik Lundh

Tommytrojan said:
thanks for your quick reply. I guess I should have included the output.
I thought I was clear in the error description.
The problem is that I never assign to 'string'. I only reference it (as
the error message correctly states). If you comment out the import
statement in the except clause the program runs fine. Now notice that
the exception hander never gets executed! Any explanation?

the language reference has the full story:

http://docs.python.org/ref/naming.html

"If a name is bound in a block, it is a local variable of that
block." /.../

"The following constructs bind names: formal parameters
to functions, import statements, class and function definitions
(these bind the class or function name in the defining block),
and targets that are identifiers if occurring in an assignment,
for loop header, or in the second position of an except
clause header. The import statement of the form "from ...
import *" binds all names defined in the imported module,
except those beginning with an underscore. /.../

A target occurring in a del statement is also considered bound
for this purpose (though the actual semantics are to unbind
the name). /.../

If a name binding operation occurs anywhere within a code block,
all uses of the name within the block are treated as references to
the current block."

</F>
 
T

Tommytrojan

Thanks for the clarification. I never ran into this before although I
have been working with Python for over 8 years. Good to learn something
new.

Cheers,
Thomas
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,055
Latest member
SlimSparkKetoACVReview

Latest Threads

Top