Python Pitfalls: Scope

about | archive


[ 2004-September-15 10:14 ]

One minor Python quirk that occasionally catches me is the fact that it does not have nested, block variable scopes like I am accustomed to in nearly every other programming language I use, like C, C#, C++, Objective C, Perl, and Java. I will give a brief example comparing Java and Python. Here is the Java version:

class test
{
	public static void main(String args[])
	{
		int one = 1;
		if ( one == 1 )
		{
			int two = 2;
			System.out.println( one ); // OUTPUT: -1
			System.out.println( two ); // OUTPUT: 2
		}
		System.out.println( one ); // OUTPUT: 1
		// COMPILE ERROR: test.java:14: cannot resolve symbol
		//System.out.println( two ); 
	}
}

In Java, the variable two exists only inside the if block. This is the way my brain has become accustomed to working. Here is the Python version:

one = 1

if one == 1:
	two = 2
	
	print one # OUTPUT: 1
	print two # OUTPUT: 2

print one # OUTPUT: 1
print two # OUTPUT: 2

Note that in this case, the variable two still exists outside of the if statement. So why is this a problem? On occasion I'll define a variable inside a loop or if statement, and then mistakenly use it afterwards. This will work until the program flow changes, for whatever reason, and then suddenly the variable is no longe defined. Here is a slightly modified example of this program to illustrate what I am talking about:

one = 1

if one == 1:
	two = 2
	
	print one
	print two
else:
	print one

print one
print two

This program has the same output as before: 1, 2, 1, 2. But what happens if we change the variable one to have the value 2? Now, we get the following output:

2
2
Traceback (most recent call last):
  File "test.py", line 12, in ?
    print two
NameError: name 'two' is not defined

Oops! Suddenly, the program crashes because the value of a variable changed. This problem could be exposed if the variable two disappeared after the if statement. This way, even if the variable one really does equal 1, the error message would still appear. However, the challenge is that Python doesn't have variable declarations, so it would have to infer where variables are first used. It would be interesting to experiment with a version of Python that had this restriction. The nice part of this is that programs written for the more restrictive Python would run without modification on the less restrictive Python, so it could be a gradual migration like Perl's use strict mode.