I am learning about variable scoping and was looking through some threads when I saw the following Python code:
a = 1
b = 2
c = 3
def foo():
print a
print b
print c
c = c + 1
def main():
foo()
main()
which prints out 1
2
and UnBoundLocalError: local variable 'c' referenced before assignment
. When I translated this to Java
public class Test1 {
static int a = 1;
static int b = 2;
static int c = 3;
public static void foo()
{
System.out.println(a);
System.out.println(b);
System.out.println(c);
c = c + 1;
}
public static void main(String[] args)
{
foo();
}
}
It prints out 1
2
3
. I am pretty sure I translated it correctly(highly embarrassing if it isn't). My question is why does Python give an error whereas Java does not? Is it something to do with different scoping or the way that they are interpreted and compiled?
Python has no variable declarations. Instead, it defines a rule that any name you assign to in a function is a local variable of that function. That means that the line
c = c + 1
in foo
makes c
a local variable, so
print c
tries to print an unassigned local variable and raises an exception.
Java has variable declarations. Your Java code declares c
outside main
and doesn't redeclare it inside, so Java knows that c
is a static variable, and the program works. A better translation of the Python code to Java might be
public class Test1 {
static int a = 1;
static int b = 2;
static int c = 3;
public static void foo() {
int c; // Now c is local, like in the Python
System.out.println(a);
System.out.println(b);
System.out.println(c);
c = c + 1;
}
public static void main(String[] args) {
foo();
}
}
The incomprehension and astonishment you had, like many people learning Python (do a research on stackoverflow.com with "referenced before assignment" expression), me comprised, is due to the fact that the documentation is sometimes badly written.
The explanation of this error is here:
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. This can lead to errors when a name is used within a block before it is bound. This rule is subtle. Python lacks declarations and allows name binding operations to occur anywhere within a code block. The local variables of a code block can be determined by scanning the entire text of the block for name binding operations.
http://docs.python.org/2/reference/executionmodel.html
In my opinion, this extract badly expresses what is performed when a code is executed:
saying "can be determined by scanning" is deceiving, it gives the impression that this scanning is optional.
Though I've never read anything about this point that would have confirmed my opinion, I personnaly think that:
- in fact this scanning IS always performed, that's not an option
- more importantly, this scanning is done before any call of the callable object that the block is defining
.
Indeed, there's an important notion to understand first:
One must realize that the term "definition" is ambiguous because it can be understood in two ways:
1/ definition = code block in a script that "defines" something
2/ definition = the execution of this code block at the moment of the execution of the script to create the defined callable object
I base these asertions on:
A block is a piece of Python program text that is executed as a unit. The following are blocks: a module, a function body, and a class definition.
http://docs.python.org/2/reference/executionmodel.html
.
A function definition defines a user-defined function object (...)
A function definition [sense 1] is an executable statement. Its execution binds the function name in the current local namespace to a function object (...)
The function definition [sense 2] does not execute the function body; this gets executed only when the function is called.http://docs.python.org/2/reference/compound_stmts.html#function-definitions
.
A function definition defines a user-defined function object
: such a beautiful tautology ! This sentence explains NOTHING. I think more useful to analyze what follows:
[sense 1] there, "definition" means "the code block (=text) that defines"
[sens 2] there, "definition" means "the execution of the defining code block"; a text (definition sense 1) doesn't execute anything, it passively lies as a text...
You see that the name "definition" is ambiguous and the doc is sometimes badly written.....
The last extract concern functions definitions but the notions can evidently be extended to classes, other callable objects. Classes are also defined by code blocks and then these two steps exist for them too: definition (sense 2= execution of the defining code block) and then call.
.
So my claim is that I'm founded to think that the scanning of the identifiers in a callable object and the determination of their scopes is performed at the moment the code block [= definition sense 1] is executed, this execution being so called "definition" [sense 2] too.
That's what I wanted to point out as the key point in my opinion.
.
PS: the use of the term "variable" in the above extract of the doc is deplorable, because "variable" is another highly ambiguous term when used in Python.
The proof it is deplorable is that the OP presents his question doing comparison of what happens in Java and what happens in Python.
If there were somewhere in the basic official doc a solid explanation of the fact that in Python the coder has no access to entities acting as "chunk of memory whose content can change" , this kind of confusion should more rarely happen.
But that's another story
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With