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