The nonlocal keyword. Features of use. Examples
Before using this theme are encouraged to review the following theme:
Contents
- 1. What is the nonlocal instruction for? General form of use
- 2. Features of using the nonlocal instruction. Difference between global and nonlocal statements
- 3. Peculiarities of using the nonlocal statement in the case when several levels of nested functions are used. Example
- 4. Requirements for enclosing functions that contain nested functions with nonlocal statements
- 5. Differences in the rules for finding names by the interpreter in the global and nonlocal statements
- 6. Examples of using the nonlocal instruction
- 7. What restrictions are imposed on nonlocal statement?
- 8. An example where multiple names are declared in a nonlocal statement
- Related topics
Search other websites:
1. What is the nonlocal instruction for? General form of use
The nonlocal instruction is used when nested functions are implemented in the program. The nonlocal instruction is intended to change the value of an enclosing function variable in the body of a nested function. Thus, the nested function has access to the variables of the enclosing functions.
Using this mechanism makes it possible to maintain modifiable information about the state, which is restored on subsequent calls to the nested function.
The general form of the use of nonlocal statement
def Fn(): nonlocal name1, name2, ..., nameN
here
- Fn() – a function that is nested in some other function;
- name1, name2, nameN – names that exist in the scope of the enclosing function. The Fn() function is nested in another enclosing function.
In the case of a simple nesting of the FnIn() function within the enclosing FnOut() function, the general form of declaring a nonlocal instruction is as follows:
def FnOut(): ... def FnIn(): nonlocal name1, name2, ..., nameN ...
here
- FnOut() – an enclosing function in which a nested function FnIn() is declared;
- FnIn() – a nested function that contains a nonlocal statement;
- name1, name2, nameN – names that are declared in the enclosing FnOut() function and used in the nested FnIn() function.
⇑
2. Features of using the nonlocal instruction. Difference between global and nonlocal statements
The nonlocal instruction is used in nested functions when you need to change variables that have been declared in enclosing functions.
The difference between nonlocal and global statements is as follows:
- the global statement allows you to change the values of variables in the global scope of the module;
- the nonlocal statement changes the value of variables in the enclosing function. The nonlocal statement has no effect for the global scope.
⇑
3. Peculiarities of using the nonlocal statement in the case when several levels of nested functions are used. Example
Example. Let several nested functions be given. The outer function Fn1() contains the embedded function Fn2(). The nested function Fn2() contains another nested function Fn3(). The functions Fn1() and Fn2() declare a variable named x1, which is assigned some value. In the Fn3() function, the variable x1 is modified using the nonlocal instruction. As a result, the variable x1 of the nearest enclosing function will change, in our case – the function Fn2().
# Instruction nonlocal # Several enclosing functions def Fn1(): # this variable does not change from the function Fn3(), # because it is overridden by the variable from the function Fn2 () x1 = 25 def Fn2(): x1 = 33 # this variable will be changed in the function Fn3() def Fn3(): nonlocal x1 x1 = 55 # Fn2.x1 = 55 Fn3() print('Fn2.x1 = ', x1) Fn2() print('Fn1.x1 = ', x1) Fn1()
The result of the program
Fn2.x1 = 55 Fn1.x1 = 25
If we remove the line x1 = 33 in the body of the function Fn2(), then the value of the variable x1 of the higher-level function, that is, the function Fn1(), will change. In this case, the program will return the result
Fn2.x1 = 55 Fn1.x1 = 55
⇑
4. Requirements for enclosing functions that contain nested functions with nonlocal statements
In order to use the nonlocal statement in a nested function, the following conditions must be met:
- the program contained code of nested functions. One of the functions is considered as enclosing, the other is nested;
- a variable was declared in the enclosing function, which is changed in the nested function. This variable must be declared before the nested function declaration.
⇑
5. Differences in the rules for finding names by the interpreter in the global and nonlocal statements
If a nonlocal instruction is used in a nested function, the interpreter does the following:
- skips the local scope of the function in which the nonlocal statement is declared;
- searches the scopes of enclosing functions starting with the nearest enclosing function.
When the global statement is used in a nested function, the interpreter searches the enclosing module’s namespace (global scope).
⇑
6. Examples of using the nonlocal instruction
Example 1. The example demonstrates access to the out variable of the enclosing FnOut() function from the FnIn() function.
# The nonlocal statement # Enclosing function FnOut() def FnOut(): out = 25 # declare out variable # The nested function which uses nonlocal statement def FnIn(): # access to the out variable of the enclosing function FnOut() nonlocal out out = 777; return # Calling the nested function FnIn() from the body of the function FnOut() FnIn() # Print the out variable print('FnOut.out = ', out) # Global scope. # Invoke function FnOut() FnOut() # FnOut.out = 777
The result of the program
FnOut.out = 777
As you can see from the result, the out variable from the FnOut() function was changed in the body of the FnIn() function due to the nonlocal instruction.
Example 2. The solution of the quadratic equation. The example demonstrates access to the variables x1, x2 of the enclosing SquareEquition() function from the nested Calc() function.
# The nonlocal statement. The solution of quadratic equation # Include a math module in order to use the math.sqrt() function import math # Declare two functions: enclosing SquareEquition() and nested Calc() def SquareEquition(a, b, c): # Declare two functions: enclosing SquareEquition() and nested Calc() x1 = None x2 = None # Nested Calc() function - fills in values x1, x2 def Calc(a, b, c): D = b*b-4*a*c if (D>=0): # access to x1, x2 enclosing SquareEquition() function nonlocal x1, x2 # declare 2 names in the nonlocal instruction x1 = (-b - math.sqrt(D))/(2.0*a) x2 = (-b + math.sqrt(D))/(2.0*a) Calc(a, b, c) return [x1, x2] # Using the function SquareEquition(), # input data print("Input a, b, c:") a = float(input('a = ')) b = float(input('b = ')) c = float(input('c = ')) roots = SquareEquition(a, b, c) print('roots = ', roots)
The result of the program
Input a, b, c: a = 1 b = 1 c = -2 roots = [-2.0, 1.0]
⇑
7. What restrictions are imposed on nonlocal statement?
The following restrictions apply to the nonlocal instruction:
- the name that is declared in the nonlocal statement must already exist in the enclosing function at the time of the call in the nested function;
- when using the statement, names are looked up only in the scope of enclosing functions. The built-in and global scopes are not searched for nonlocal names, even if such names already exist in those scopes (see example below).
Example. If you try the following example
# Restrictions that are imposed to nonlocal statement D = 'Hello' # Declare a global name def FnOut(): def FnIn(): # Trying to bind name D to global name D nonlocal D D = 'world!' # Invoke function FnIn() from the function FnOut() FnIn() print('FnIn.D = ', D) # Call FnOut() function from module scope FnOut()
the interpreter will throw an error:
SyntaxError: no binding for nonlocal 'D' found
This means that the name D must be previously declared in the enclosing FnOut() function, and not in the global scope. For example, the FnOut() function can be changed as follows
... def FnOut(): D = 'Hello' def FnIn(): # the name D binds with the name D of the enclosing function nonlocal D D = 'world!' # Invoke the FnIn() function from the body of the FnOut() function FnIn() print('FnIn.D = ', D) ...
After that, the program will work and give the result
FnIn.D = world!
⇑
8. An example where multiple names are declared in a nonlocal statement
# Addition of complex numbers (a1+b1*j)+(a1+b2*j) def ComplexAdd(a1, b1, a2, b2): a3 = 0 b3 = 0 def Add(): nonlocal a3, b3 # Using two names in the nonlocal statement a3 = a1+a2 b3 = b1+b2 Add() return [a3, b3] result = ComplexAdd(2, 3, -1, 4) print('result = ', result) # result = [1, 7]
⇑
Related topics
- Concept of function. General form. Examples of declaring and using functions
- Scopes of names. Local and global names. Visibility rules for names. LEGB rule. The global keyword. Overriding names in function
- Nested functions. Nested scopes. Name search rules in case of nested functions. Factory functions. Passing value to a nested function
⇑