The Global and Nonlocal Keywords in Python

Maghfoor Ahmad Bilal
The Startup
Published in
4 min readMay 6, 2020

Why do they exist?

Photo by Kyle Glenn on Unsplash

Using global variables is considered bad practice (if this comes as a surprise to you, read this explaining why).

To discourage their use, Python needs you to explicitly state when you want to use them.

Python is Different in Scoping

You have to explicitly state because Python searches for variables referred to in the local scope first, then the enclosing scope, then the global scope, and uses the first one it encounters.

This is in contrast to many other languages that search top-down for variables i.e. first globally, then locally. For example, in C++ if a global variable is already present, any changes we make to it inside a function will reflect in its original space:

Global variable behavior in C++

Whereas in Python, even if a variable with the same name exists outside the function, the assignment operator will create a new one locally:

Local scope first.

Globally, the value of v remains unchanged because Python created a new local v, as if no other v existed, and when foo() exited v was garbage-collected away.

Using Global

Bare in mind global is not required when you’re just trying to read. You are allowed to only refer to variables defined above the current scope. Python will give you the value of the first v it finds going up, if no v was present locally.

Whenever you want to modify a global variable inside of a function, define it with global just once in the current scope before doing anything with it, like so:

Basic usage of global

And if there wasn’t a global variable v defined already, Python will use the assignment operator to create one in the global scope.

Creating a global from inside

That means you can define a new global variable from any nested scope, not just from the global scope itself.

Now onto nonlocal. But first…

The Enclosing Scope

If a function is defined inside of another function, the inner function can read variables present in the outer function. So we say the scope of the outer function is also the enclosing scope of the inner function.

By the way, this pattern of nesting a function inside another function, and then the inner function having access to the outer function’s variables (if any), is called a closure (also common in JavaScript). Python decorators are based on closures. They’re also used to implement data privacy in JavaScript. Here’s an easy explanation of closures.

The cool thing about enclosing scopes is that if we were to return the inner function as an object, the enclosing variables will remain intact on subsequent calls to inner, even though outer() had finished and its local scope was destroyed when we used it to get inner() in the first place.

Enclosing scope remains intact

But we would really be taking advantage of enclosing scopes only if we did something with v apart from just reading it, like incrementing and keeping track of the number of times inner() was called.

Reading, as I said, doesn’t require any keywords. Modifying v, however, from inner() won’t work simply by assigning to it (that would create a local variable) nor by global (that would create a global variable).

Therefore, nonlocal was introduced to allow modification of variables present in the enclosing scope, which otherwise wasn’t possible.

Using Nonlocal

From the documentation,

The nonlocal statement causes the listed identifiers to refer to previously bound variables in the nearest enclosing scope excluding globals.

Of course there can be multiple enclosing scopes, so the nearest one going up will be your reference.

Let’s try the function count thing now.

Using nonlocal to modify enclosing state

Notice how v in the global scope remained untouched. To drive the point home, let’s do two levels of nesting:

Two levels of nesting. V still remains intact.

Invoking outer() returns the middle function object, which we invoke by the second set of parenthesis to get the inner function object. Here, both outer() and middle() make up the enclosing scope of inner(). But nonlocal will refer to the nearest one.

To learn more about scoping in Python in detail, check out this great piece.

Things to Remember

  • Read variables however you like.
  • Use global if you wish to modify a variable’s value for good. Again, that’s not good design.
  • Whatever you do after defining a variable with global, you’re doing it in the zero indentation of the script.
  • Use nonlocal to modify variables in the enclosing scope of a function.
  • Nonlocal is not global, and it’s obviously not local. It’s the thing in between.

--

--

Maghfoor Ahmad Bilal
The Startup

A student of Computer Science. Love Python and developing stuff from scratch.