Python: Why is global needed only on assignment and not on reads?

Question:

If a function needs to modify a variable declared in global scope, it need to use the global declaration. However, if the function just needs to read a global variable it can do so without using a global declaration:

X = 10
def foo():
    global X
    X = 20 # Needs global declaration
def bar():
    print( X ) # Does not need global

My question is about the design of Python: why is Python designed to allow the read of global variables without using the global declaration? That is, why only force assignment to have global, why not force global upon reads too? (That would make it even and elegant.)

Note: I can see that there is no ambiguity while reading, but while assigning it is not clear if one intends to create a new local variable or assign to the global one. But, I am hoping there is a better reason or intention to this uneven design choice by the BDFL.

Asked By: Ashwin Nanjappa

||

Answers:

Look at this code:

from module import function

def foo(x):
    return function(x)

The name function here is a global. It would get awfully tedious if I had to say global function to get this code to work.

Before you say that your X and my function are different (because one is a variable and the other is an imported function), remember that all names in Python are treated the same: when used, their value is looked up in the scope hierarchy. If you needed global X then you’d need global function. Ick.

Answered By: Ned Batchelder

With nested scopes, the variable lookups are easy. They occur in a chain starting with locals, through enclosing defs, to module globals, and then builtins. The rule is the first match found wins. Accordingly, you don’t need a “global” declaration for lookups.

In contrast, with writes you need to specify which scope to write to. There is otherwise no way to determine whether “x = 10” in function would mean “write to a local namespace” or “write to a global namespace.”

Executive summary, with write you have a choice of namespace, but with lookups the first-found rule suffices. Hope this helps 🙂

Edit: Yes, it is this way “because the BDFL said so”, but it isn’t unusual in other languages without type declarations to have a first-found rule for lookups and to only require a modifier for nonlocal writes. When you think about it, those two rules lead to very clean code since the scope modifiers are only needed in the least common case (nonlocal writes).

Answered By: Raymond Hettinger

Because explicit is better than implicit.

There’s no ambiguity when you read a variable. You always get the first one found when searching scopes up from local until global.

When you assign, there’s only two scopes the interpreter may unequivocally assume you are assigning to: local and global. Since assigning to local is the most common case and assigning to global is actually discouraged, it’s the default. To assign to global you have to do it explicitly, telling the interpreter that wherever you use that variable in this scope, it should go straight to global scope and you know what you’re doing. On Python 3 you can also assign to the nearest enclosing scope with ‘nonlocal’.

Remember that when you assign to a name in Python, this new assignment has nothing to do with that name previously existing assigned to something else. Imagine if there was no default to local and Python searched up all scopes trying to find a variable with that name and assigning to it as it does when reading. Your functions’ behavior could change based not only on your parameters, but on the enclosing scope. Life would be miserable.

Answered By: Pedro Werneck

You say it yourself that with reads there is no ambiguity and with writes there is. Therefore you need some mechanism for resolving the ambiguity with writes.

One option (possibly actually used by much older versions of Python, IIRC) is to just say writes always go to the local scope. Then there’s no need for a global keyword, and no ambiguity. But then you can’t write to global variables at all (without using things like globals() to get at them in a round-about way), so that wouldn’t be great.

Another option, used by languages that statically declare variables, is to communicate to the language implementation up-front for every scope which names are local (the ones you declare in that scope) and which names are global (names declared at the module scope). But Python doesn’t have declared variables, so this solution doesn’t work.

Another option would be to have x = 3 assign to a local variable only if there isn’t already a name in some outer scope with name x. Seems like it would intuitively do the right thing? It would lead to some seriously nasty corner cases though. Currently, where x = 3 will write to is statically determined by the parser; either there’s no global x in the same scope and it’s a local write, or there is a global x and it’s a global write. But if what it will do depends on the global module scope, you have to wait until runtime to determine where the write goes which means it can change between invocations of a function. Think about that. Every time you create a global in a module, you would alter the behaviour of all functions in the module that happened to be using that name as a local variable name. Do some module scope computation that uses tmp as a temporary variable and say goodbye to using tmp in all functions in the module. And I shudder to think of the obscure bugs involving assigning an attribute on a module you’ve imported and then calling a function from that module. Yuck.

And another option is to communicate to the language implementation on each assignment whether it should be local or global. This is what Python has gone with. Given that there’s a sensible default that covers almost all cases (write to a local variable), we have local assignment as the default and explicitly mark out global assignments with global.


There is an ambiguity with assignments that needs some mechanism to resolve it. global is one such mechanism. It’s not the only possible one, but in the context of Python, it seems that all the alternative mechanisms are horrible. I don’t know what sort of “better reason” you’re looking for.

Answered By: Ben
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.