Default scope of variables

Steven D'Aprano steve+comp.lang.python at pearwood.info
Wed Jul 3 23:27:25 EDT 2013


Recently, there was a thread where people discussed variable 
declarations, with a couple people stating that they wished that Python 
required you to declare local variables, instead of globals.

I'm sure they have their (foolish, pathetic) *wink* reasons for this, but 
I thought I'd explain why I think Python makes the right decision to 
require declarations for globals but not locals.

I was reading some Javascript today, and wading through masses of code 
that looked something like this:

function update_results() {
    var n1 = foo;
    var n2 = bar;
    var m1 = foobar;
    var m2 = foobarbaz;
    var fe = n1 * m1;
    var fi = n2 * m2;
    var fo = n1 * m2;
    var fum = n2 * m1;
    ... 
    }

and so on for about a page and a half. Looking at that page in my editor, 
with that solid column of bold "var" keywords, it struck me just how 
redundant that enormous column of "var"s was. Of course they were 
variables, what else would they be?

Larry Wall, the creator of Perl, is fond of discussing Huffman coding as 
it relates to programming syntax. Common things should be short, rare 
things can be longer. Wall is not concerned about saving a few bytes in 
your source files, but about programmer effort: typing effort, reading 
effort, mental processing effort. Which do you prefer?

total = subtotal + extra

set total to subtotal plus extra

Even though the second is only 8 more characters, I bet you prefer the 
first version.

With respect to the Huffman coding of declarations, Javascript gets it 
backwards. Locals ought to be more common, but they require more typing. 
Locals are safer, better, more desirable than globals, and so it should 
be easier to use locals than globals, not the other way around. Having to 
declare "give me the safe kind of variable", while getting the harmful[1] 
kind of variable for free, strikes me as arse-backwards. Lazy, naive or 
careless coders get globals[2] by default or accident. That's bad.

Not just theoretically bad. Here's a real-world case where a single 
missed "var" lead to something much, much worse than a crash: code that 
kept going, but doing the wrong thing.

http://blog.safeshepherd.com/23/how-one-missing-var-ruined-our-launch/


The two situations:

1) Accidentally scope an intended local as global;
2) Accidentally scope an intended global as local;

are not symmetrical. In the first case, you get multiple invocations of 
your function overwriting each other's data. Confusion reigns, but the 
function calls will likely continue, pumping out garbage results instead 
of crashing. The likely result is typically fail-unsafe rather than fail-
safe. [Aside: fail-safe does not mean "safe from failing", but "fails in 
a safe manner".]

In the second case, any failure is far more likely to result in the 
function call failing hard with an exception (fail-safe) rather than 
churning out bad results, since each call of the function gets its own 
set of locals rather than using those from some other call.

So in Javascript, it's easy to get unsafe globals by accident; in Python, 
it's hard to get unsafe globals by accident. In my opinion, Python gets 
it right.




[1] As in, "Global variables considered harmful", one of the classic 
papers of computer science: 
http://c2.com/cgi/wiki?GlobalVariablesConsideredHarmful

[2] Actually, Javascript gives you something a little closer to Python's 
"nonlocal" by default: each enclosing function is searched for a matching 
variable, terminating at the global scope.


-- 
Steven



More information about the Python-list mailing list