Introduction
The Python nonlocal
keyword is used to access and modify variables from an outer (but not global) scope in nested functions (i.e. non-local variables). It tells Python that a variable assigned in a nested function should refer to a variable in the nearest enclosing scope that is not global. Otherwise, Python will create a new variable in the local scope of the nested function.
It is similar to the global
keyword, but operates on outer local scopes of nested functions rather than global scopes. Because of this similarity, the lesson about the global keyword is a recommended prerequisite.
Using the Python nonlocal Keyword
To use the nonlocal
keyword, simply write nonlocal
followed by the variable name within a nested function to reference an outer (but not global) scope variable:
nonlocal variable_name
The above statement will ensure that variable_name
refers to a variable in an outer (non-global) scope.
Example:
def outer_function(): outer_var = 10 def inner_function(): nonlocal outer_var outer_var = 20 inner_function() print("Outer variable:", outer_var) outer_function()
Output:
Outer variable: 20
In the example above, the nonlocal
statement inside the inner_function()
(line 5) indicates that outer_var
refers to the variable declared in the outer function outer_function()
(line 2). When the inner function modifies outer_var
by setting it to 20 (line 6), it is the variable in the outer scope that changes. Consequently, when outer_var
is printed outside the inner function (line 9), the output is 20.
What Happens Without nonlocal
If you don’t use the nonlocal
keyword and attempt to assign a value to a variable from an outer scope within a nested function, Python will create a new local variable in the nested function instead.
Example:
def outer_function(): outer_var = 10 def inner_function(): outer_var = 20 # This is a local variable here! inner_function() print("Outer variable:", outer_var) outer_function()
Output:
Outer variable: 10
The only difference between this and the previous example’s code is the removal of the nonlocal outer_var
statement in the inner_function()
. Now, when outer_var
is assigned a value inside inner_function()
(line 5), it creates a new local variable within that function’s scope, not modifying the variable from the outer function. Therefore, when outer_var
is printed (line 8), it remains unchanged and retains the value of 10.
nonlocal Does Not Create a Variable If It Does Not Exist
Unlike a global
statement, nonlocal
does not create a variable in an outer scope if one does not exist yet. The following example demonstrates this by generating an error.
Example:
def outer_function(): def inner_function(): nonlocal outer_var outer_var = 20 inner_function() print("Outer variable:", outer_var) outer_function()
Output:
... SyntaxError: no binding for nonlocal 'outer_var' found
The above example generates a SyntaxError
exception because the nonlocal
statement in inner_function()
(line 3) references a variable that does not exist yet.
nonlocal Will Bind to Variables in Higher Levels of Nesting
While multiple levels of nesting in functions is rare and should be avoided if possible for the sake of code simplicity and clarity, nonlocal
does support it. If it doesn’t find the variable in a parent function, it will keep going up the hierarchy of nested functions until it finds one.
Example:
def outer_outer_function(): outer_outer_var = None def outer_function(): def inner_function(): nonlocal outer_outer_var outer_outer_var = 20 inner_function() print("Outer outer variable:", outer_outer_var) outer_function() outer_outer_function()
Output:
Outer outer variable: 20
The example above has three levels of nested functions. inner_function()
(line 5) is in outer_function()
(line 4) , which is in outer_outer_function()
(line 1). inner_function()
references outer_outer_var
in the nonlocal
statement (line 6), which is a variable first declared by outer_outer_function()
, two nesting levels up.
Drawbacks of Using Non-Local Variables
The use of non-local variables suffers from the same readability, maintainability, and testing drawbacks as the use of global variables within functions. However, because non-local variables are contained within the smaller scope of a single parent function, those drawbacks are less severe.
If you keep your functions small, the convenience of referencing non-local variables directly within inner functions rather than passing them as arguments might outweigh their drawbacks.
Summary & Reference for the Python nonlocal Keyword
The Python nonlocal
keyword lets you modify and access variables from outer scopes within nested functions (a.k.a non-local scopes). Without it, functions attempting to assign a value to an outer scope variable create a local variable with the same name instead, potentially leading to unintended behavior.
To use the nonlocal
keyword, simply write nonlocal
followed by the variable name within a nested function to reference an outer (but not global) scope variable.
nonlocal variable_name
If the nonlocal
keyword is omitted within a nested function, Python will create a new local variable with the same name as the variable from the outer scope.
def outer_function(): outer_var = 10 def inner_function(): outer_var = 20 # This is a local variable here! inner_function() print("Outer variable:", outer_var) outer_function() # --> 10 - not modified by inner_function()
The nonlocal
keyword does not create a variable in an outer scope if it doesn’t already exist, which differs from the behavior of the global
keyword.
def outer_function(): def inner_function(): nonlocal outer_var # This will raise a SyntaxError outer_var = 20 inner_function() print("Outer variable:", outer_var) outer_function() # --> SyntaxError: no binding for nonlocal 'outer_var' found
While using nonlocal
can be convenient, excessive reliance on non-local variables can lead to code readability and maintainability issues. It’s recommended to use non-local variables judiciously and consider alternative approaches for clearer code structure.