Navigate Python Global, Local and Nonlocal Variable

Photo by Timothy Dykes on Unsplash

If you are like me who have a few months experience of Python, then you might be in the same position as me — know something about Python, but not enough. So I spent sometime to gather bits and pieces of scattered knowledge to dig deeper into Python. In this blog, the piece will be the local, global and nonlocal variables.

Scenario A: declare a global and local variable and read separately

Scenario B: declare a global and read it in local

Note here we declare a global variable “This is global!”and in the body of f() there is only “print(s)” trying to access the global variable, i.e., there is no local variable. So the print statement will just access the global variable as it is.

Scenario C: declare a global variable and modify it in local

The above is straightforward, as you try to modify a global variable directly before printing it out. Look at below though. Note that the error persists if you switch the order, compare it with above examples.

What we are doing here is

  • first access global variable s with a print(s),
  • and then assign a new value to s

By assigning we are creating a local variable, as any variable modified or created inside a function is local, if it hasn’t been declared as a global variable.So we have s as both global and local variable in the same scope, and since Python thinks that we actually want a local variable due to the assignment to s, so the first print statement before the assignment raises an error.

Scenario D: declare a global variable in local through global keyword

In above example, we use a global keyword for a variable which is inside a function so that it can be modified locally. So:

  • the first print statement still returns the unmodified global var in local scope,
  • the next print returns the modified version in the local scope,
  • the last one returns the modified version in the global scope.

Note that you can even declare a global variable in a local scope and only reference it in the outer scope:

Scenario E: declare a global variable in a nested function

As you can see, a variable defined in nested scope (also a local scope) of f will remain untouched. The first print statement reference the local variable “This is not global!” . The next print statement still reference the same variable “This is not global!” as the global variable s is declared but not accessed from the global scope yet, which is done in the last print statement.

So a variable defined inside of a function is local unless it is explicitly marked as global: s = “This is not global!” .

In Python, variables that are only referenced inside a function are implicitly global. If a variable is assigned a value anywhere within the function’s body, it’s assumed to be a local unless explicitly declared as global. — doc

Scenario F: declare a nonlocal variable

Let’s first have an example without all these magic keywords:

Now add the nonlocal keyword. Nonlocal variables are used in nested functions , which means that the variable can be neither in the local nor the global scope. So now the local()'s x is now also f()'s x:

However, note that the name of the variable listed in nonlocal statement must pre-exist, otherwise an error will raise (this is different to the global keyword).

Names listed in a nonlocal statement, unlike those listed in a global statement, must refer to pre-existing bindings in an enclosing scope (the scope in which a new binding should be created cannot be determined unambiguously).

Names listed in a nonlocal statement must not collide with pre-existing bindings in the local scope.

doc

Scenario G: declare variables in a multi-level nested scope

So now it’s time to mix them together, what if we add another level of nested scope?

See that only the closest declaration s in inner_f() is targeted with the nonlocal keyword. This is because assignment of an object in python is recursively defined:

If the target is an identifier (name):

- If the name does not occur in a global or nonlocal statement in the current code block: the name is bound to the object in the current local namespace.

- Otherwise: the name is bound to the object in the global namespace or the outer namespace determined by nonlocal, respectively.

- The name is rebound if it was already bound. This may cause the reference count for the object previously bound to the name to reach zero, causing the object to be deallocated and its destructor (if it has one) to be called.

Hope the above examples won’t confuse you further. Feel free to copy the code and play around in repls.

Happy Reading!

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store