I fixed a bug today which was mildly interesting. It was caused by a local variable in a function having the same name as an unrelated imported module which was referenced earlier in the function. So the code was of this shape:
import x
...
def f():
x.g()
...
x = a
When
g
was called, an error occurred with the message "local variable
x
referenced before assignment". Now when I was debugging this, all I saw at first was the
x.g()
line (since that's the line the error occurred at), and I scrolled up, trying to find where the
x
variable had been defined, eventually finding that
x
was the name of the module. This left me rather confused, since I couldn't imagine how the module name
x
was getting interpreted as the name of a local variable when it hadn't been reassigned at any point earlier in the code.
Of course, the answer is that the
later reassignment was responsible. Python (like most programming languages, I believe) allocates local variables on the call stack, so it has to know what local variables there are as it calls the function, before it executes the function body. So it effectively does an initial pass over the body looking for assignments, and notices the
x = a
line and rebinds the name
x
to a local variable, before it executes the
x.g()
line.
Now I see why C89 requires you to put all variable declarations at the start of a function! OK, I don't know if this was ever the actual rationale behind that restriction, but it does seem like a good reason for it. The C89 restriction makes it clear that local variable names have to be valid across the whole body of a function, not just from the line on which they are declared onwards.