In previous articles, we learned about following topics:
Understanding Scope in Programming
- The part of a program where a variable name can be accessed is called its scope.
- Scope defines the area of the program in which a name can be accessible and different operations can be performed on that name.
- Name can be of a variable, function, class or any object.
- In the scope, we can use the given name to perform different operations like access, update and delete.
- Not all variables are accessible from every part of the program.
Generally, in the scope of a program, a variable can be declared only once with the same name. But, it’s possible to declare variables with the same name in different scopes within the same program. Changing the value of a variable within a scope, does not impact its value outside that scope, even if the variables are of same name.
Scope of Code Blocks in Programming
- Code block is defined as an area, which is separated from other sections or blocks of the program. For example: in a program, functions, classes, conditional statements and, loops are independent or separate code blocks.
- In Python, all variables are scoped to the code block, it means
- In the code block, the variable can be declared and assigned values.
- Variables can be accessed, updated and deleted within that code block.
- Python uses indentation to define a code block, it grouped the code under its parent statements like function, class, module or script file.
Understanding Variable Scope in Python
Python offers various levels of variable scope, each determining where a variable can be accessed and modified:
- Local Scope
- Global Scope (using the global keyword)
- Nonlocal Scope (using the nonlocal keyword)
- Enclosing Scope
- Built-In Scope
- In Python, “local scope” is the default scope, which also referred to as the “scope of the code block.“
- Unless otherwise specifically defined, all variables declared within a code block have local scope.
Python’s global keyword is used for modifying a variable’s scope when necessary. This “global” keyword is of significant use when working with scopes for a variable.
Local Scope in Python
Description of Local Scope:
- Variables with local scope are declared inside a code block.
- Variables declared within this code block have local scope, which is specific to that declaration block only.
- Local variables cannot be accessed outside the block in which they were declared.
Program – Local Scope Example
Lets understand local scope in Python with a program.
def func_local_variable():
shbytes_local = "This is local variable!!"
print(shbytes_local)
func_local_variable()
print(shbytes_local)
Output of the local scope program
Traceback (most recent call last):
File "D:\local_scope.py", line 7, in <module>
print(shbytes_local)
^^^^^^^^^^^^^
NameError: name 'shbytes_local' is not defined
This is local variable!!
Let’s understand local scope with a program. Here, we define a variable named shbytes_local
. This variable is declared inside the function func_local_variable()
. This makes this variable local to this function, which means this variable can only be accessed within func_local_variable()
.
We print the shbytes_local
variable’s value inside func_local_variable()
, where its value is displayed. But when we are trying to print shbytes_local
outside of the function, then it results in a NameError
– indicating that the variable shbytes_local
is not available outside its defined function.
Key Points from the above program:
- By default, a variable has a local scope and is accessible only within its local scope.
- The local scope is defined by the block or area where the variable is declared.
- Attempt to access a variable outside of its scope will generate an error.
Examples of Local Scope in Python
Variables can be declared outside of any code block, which gives them a larger scope. This allows them to be used with in the sub-code blocks as well. Below are examples of local scope used with functions, classes and modules.
Variable Declared Directly inside a Function
- Variables declared directly inside a function can be accessed inside the sub code blocks of that function.
- These variables can be accessible inside the conditional statements and loops which are inside that function.
- These variables can also be passed as arguments to other functions from within the defined function.
Program – Function Local Scope Variable
def local_function_scope_variable():
shbytes_local = 0
while(shbytes_local < 10):
shbytes_local += 1
if(shbytes_local %2 == 0) :
print(f'{shbytes_local} is Even')
else:
print(f'{shbytes_local} is Odd')
local_function_scope_variable()
Program Output – Function Local Scope Variable:
1 is Odd
2 is Even
3 is Odd
4 is Even
5 is Odd
6 is Even
7 is Odd
8 is Even
9 is Odd
10 is Even
Variable declared directly inside a Class
- Variables can be declared directly inside a Class, called as class level variables
- These class level variables can be accessed directly inside the class
- These variables can be passed as an argument to the functions using the class scope
Program – Class Local Scope Variable
class Shbytes:
shbytes_local = 0
print(shbytes_local)
def func_scope_variable(number):
while (number < 10):
number += 1
if (number % 2 == 0):
print(f'{number} is Even')
else:
print(f'{number} is Odd')
Shbytes.func_scope_variable(Shbytes.shbytes_local)
Program Output – Class Local Scope Variable:
0
1 is Odd
2 is Even
3 is Odd
4 is Even
5 is Odd
6 is Even
7 is Odd
8 is Even
9 is Odd
10 is Even
Points to Note from the Program Example:
- The variable
shbytes_local
is directly accessible within the Class where it was declared. This variable value can be printed directly from the Class. - This variable
shbytes_local
, can also be accessed using class name likeShbytes.shbytes_local
and can be passed as a function argument.
Variables declared directly inside Module
- Variables declared directly within a module are accessible throughout the module.
- However, they are limited to the module boundary, meaning variables from one module cannot be used in another module.
Program – Module Local Scope Variable
shbytes_global = "This is global variable!!"
def func_global_variable():
print(shbytes_global)
func_global_variable()
print(shbytes_global)
Program Output – Module Local Scope Variable
This is global variable!!
This is global variable!!
In the example, we defined a variable shbytes_global
outside of any code block, directly within the module. This allows shbytes_global
to be used anywhere within the module, and we demonstrate this by printing its value inside func_global_variable()
.
global
Keyword in Python
The We can declare two different variables with the same name at different scope levels. For instance, a variable with name x
can be declared both as a global variable and another variable x
declared as local variable at different scope level.
But the same variable cannot have two scopes at the same time. A variable can only have either a global scope or local scope. The global
keyword allows a local variable to be promoted to a global variable.
Program – global
Keyword Example
def func_local_variable():
global shbytes_local # declared locally but made global
shbytes_local = "This is local variable with global scope!!"
print(shbytes_local)
func_local_variable()
print(shbytes_local)
In this example, the variable shbytes_local
is defined within the function func_local_variable()
but declared using the globa
l
keyword. Although the variable is defined locally, the global
keyword allows this variable to be accessed outside of the function scope. When we print the value of shbytes_local
outside the func_local_variable()
function, the value can still be accessed and printed.
Program Output – global
Keyword Example
This is local variable with global scope!!
This is local variable with global scope!!
If we hadn’t defined the variable shbytes_local
with the global
keyword, as done in the local scope example, it would have resulted in a NameError
: name ‘shbytes_local’ is not defined.
Enclosing Scope in Python
Enclosing scope is significant while working with nested functions. In nested functions, variables declared in an outer function have a higher scope. This means, variables declared in an outer function, can be used in an inner function, but variables declared in an inner function, cannot be accessed in the outer function.
Due to this enclosing scope, variables declared in a function are only accessible within that function and its nested child functions.
Also, although variables declared in an outer function can be accessed in an inner function, any changes to the outer variable’s value within the inner function will remain local to the inner function and won’t affect the variable value in outer function.
- A program always uses the variable, whose scope is closest to it.
- This concept of enclosing scope does not apply to the nested structure of if statements and loops..
Program 1 – Enclosing Scope Example
def outer():
outer_counter = 1
def inner():
inner_counter = 2
print("outer counter : ", outer_counter)
print("inner counter : ", inner_counter)
inner()
print("outer counter in func_outer : ", outer_counter)
outer()
Program 2 – Enclosing Scope Example
def outer():
outer_counter = 1
def inner():
inner_counter = 2
outer_counter = 3
print("outer counter : ", outer_counter)
print("inner counter : ", inner_counter)
inner()
print("outer counter in func_outer : ", outer_counter)
outer()
- In Program 1, we are not updating the value of the variable
outer_counter
in theinner()
function, but in Program 2, we are updating the value of the variableouter_counter
in theinner()
function. - In both programs, we can access the variable
outer_counter
inside theinner()
function. However, in Program 2, when we re-declare the variableouter_counter
inside theinner()
function, thisouter_counter
variable will use it’s closest scope which is local scope. So,outer_counter
variable defined withininner()
function will be a separate variable with local scope. - In Program 2, although both variables share the same name,
outer_counter
, but they both are distinct variables. - The program will always use the variable closest to its scope.
Output of the above programs for enclosing scope
outer counter : 1
inner counter : 2
outer counter in func_outer : 1
outer counter : 3
inner counter : 2
outer counter in func_outer : 1
- From the output of Program 1, variable
outer_counter
always refers to the variable declared in theouter()
function, so its value is consistently 1. - In Program 2, within the
inner()
function,outer_counter
refers to the variable withinner()
function scope, whereas in theouter()
function,outer_counter
refers to theouter()
function scope. Hence, their values are different => 3 and 1.
If we want to use the same variable declared in the outer()
function without re-declaring it in the inner()
function, we can use the nonlocal
keyword.
nonlocal
Keyword in Python
In the enclosing scope section, we have observed:
- A variable with the same name declared inside an
inner
function is treated as a new variable with the inner function’s scope. - If we don’t want to declare another variable with the same name inside
inner
function but want to use the same variable declared inouter
function, then we can usenonlocal
keyword.
nonlocal
Keyword
Properties of - The
nonloc
al
keyword was introduced from Python 3. n
onlocal
keyword addresses the limitations of the enclosing scope.- Using
nonlocal
keyword, variables declared in outer function can be used in inner function and their values can be changed inside the inner function, which will be reflected to outer function as well. - The nonlocal keyword works only with variables declared in a nested function structure.
- It cannot be used to change the variables declared with module scope.
- In nested functions, nonlocal variables refer to the closest parent variable in the hierarchy and will take the first reference that it found in its parent scope.
- If no variable reference exists in the parent hierarchy of nested functions, a
SyntaxError
is raised: “no binding fornonlocal
‘variable_name’ found”.
nonlocal
Program to Understand Parent Hierarchy
Let’s understand how the reference for a nonlocal
variable is taken from its parent hierarchy through an example.
- If no variable is present in the parent hierarchy then
SyntaxError
will be raised.
Program 1
def nonlocalscope():
nonlocal a
a = "changing to non-local!"
print(a)
a = "global variable!"
nonlocalscope()
Program 2
def localscope():
a = "local variable!"
def nonlocalscope():
nonlocal a
a = "changing to non-local!"
print(a)
nonlocalscope()
print(a)
localscope()
In Program 1, we define a function named nonlocalscope()
where we declare a nonlocal
variable a
. Since a
is not declared within any parent hierarchy function, and variables declared at the module level can’t be assigned as nonlocal
, it results in a SyntaxError
– “no binding for nonlocal ‘a’ found.”
In Program 2, we use a nested function structure. Here, the variable a
is declared in the outer localscope()
function, and a nonlocal
variable a
is declared in its inner nonlocalscope()
function. Using nonlocal
in the inner function will not declare a new variable but will instead search for a
in the parent scope. When it finds the reference in the parent localscope()
function, it uses that reference.
By using the parent hierarchy reference, if we modify the variable value in the inner function, the change is reflected in the outer function as well—something that wasn’t possible with just the enclosing scope. If no reference for the variable a
is found in its parent hierarchy, it raises a SyntaxError
– “no binding for nonlocal ‘a’ found.”
Output of the above programs for enclosing scope
File "D:\nonlocal_hierarchy.py", line 2
nonlocal a
^^^^^^^^^^
SyntaxError: no binding for nonlocal 'a' found
changing to non-local!
changing to non-local!
- From the Program 1 output, it throws a
SyntaxError
– “no binding for nonlocal ‘a’ found.” - From the Program 2 output, the value for variable
a
from thelocalscope()
function is changed and printed twice.
nonlocal
Program to Understand Its Scope
In this program, the same concepts are used as explained in the previous section.
Program 1
def func_outer():
outer_counter = 1
print("outer counter in func_outer : ", outer_counter)
def func_inner():
inner_counter = 2
outer_counter = 3
print("outer counter : ", outer_counter)
print("inner counter : ", inner_counter)
func_inner()
print("outer counter in func_outer : ", outer_counter)
func_outer()
Program 2
def func_outer():
outer_counter = 1
print("outer counter in func_outer : ", outer_counter)
def func_inner():
inner_counter = 2
nonlocal outer_counter
outer_counter = 3
print("outer counter : ", outer_counter)
print("inner counter : ", inner_counter)
func_inner()
print("outer counter in func_outer : ", outer_counter)
func_outer()
- In Program 1, the variable
outer_counter
is declared in thefunc_outer()
function. We are using this variable inside thefunc_inner()
function without thenonlocal
keyword. This program’s output will be similar to the enclosing scope program output, as explained previously. - In Program 2, the variable
outer_counter
is declared in thefunc_outer()
function, and we are usingouter_counter
variable inside thefunc_inner()
function with thenonlocal
keyword. In this case, theouter_counter
variable will be referenced from the declaration in its parentfunc_outer()
function.
Output of the above programs for nonlocal keyword
outer counter in func_outer : 1
outer counter : 3
inner counter : 2
outer counter in func_outer : 1
outer counter in func_outer : 1
outer counter : 3
inner counter : 2
outer counter in func_outer : 3
Built-in Scopes in Python
Python also has a built-in scope that does not apply to user-defined variables. Built-in scope is the widest scope and applies to all available special reserved keywords. We can call these keywords from anywhere in the programs or from any modules. These keywords are part of the Python core installation, reserved for specific purposes, and cannot be used for any other purpose in the program.
Reserved keywords are:
- False
- None
- True
- and
- as
- assert
- break
- class
- continue
- def
- del
- elif
- else
- except
- finally
- for
- from
- global
- if
- import
- in
- is
- lambda
- nonlocal
- not
- or
- pass
- raise
- return
- try
- while
- with
- yield
Summary
This article explains the concept of scope in programming, focusing on variable scopes in Python. It defines scope as the context in which a variable is accessible, detailing the types of scopes in Python: local, global
, nonlocal
, enclosing and built-in. Local variables are confined to their specific code blocks, while global variables can be accessed throughout the module. The article also discusses the nonlocal
keyword, which allows inner functions to reference and modify variables from outer functions. Through clear examples, readers will understand the significance of variable scope for effective code organization and data management in Python.
Python Code – Github Repository
Code snippets and programs related to Variable Scopes in Python, can be accessed from GitHub Repository. This GitHub repository all contains programs related to other topics in Python tutorial.
Interview Questions & Answers
What is the LEGB rule in Python?
LEGB rule is the order in which Python looks for a variables based on their scope. LEGB stands for:
- Local – Local scope is the innermost scope, i.e., within the current function or code block.
- Enclosing – This is the scope of any enclosing functions, in case of nested functions.
- Global – Module-level scope or global scope
- Built-in – The outermost scope, containing built-in names and functions.
In Python, reference to a variable is defined based on the LEGB order. Python will search these scopes in the LEGB order and will assign the first occurrence it finds.
global
keyword inside a function?
What happens if we modify a global variable without the If we modify a global variable inside a function without using the global
keyword, Python will consider it as a local variable within that function. This can lead to an error if the variable hasn’t been initialized within the function.
x = 10 # variable defined at module level but not marked global
def modify_variable():
x = 20 # This will create a new local variable 'x'
print(x) # This will print the value of local variable 'x'
modify_variable() # Output: 20, from local variable 'x'
print(x) # Output: 10 (module level variable 'x' is unchanged)
nonlocal
is necessary?
Give a scenario where nonlocal
is necessary when you have a nested function and you want to modify a variable from the enclosing function (not the global
scope).
def counter():
count = 0 # Variable count is in the enclosing scope
def increment():
nonlocal count # With nonlocal, it is using the variable from enclosing scope
count += 1 # increase the value of enclosing scope variable count
return count
return increment
counter_function = counter() # This will return the increment() function assigned to variable counter_function
print(counter_function()) # call to increment() function, Output: 1, initially count was 0
print(counter_function()) # call to increment() function, Output: 2, count was 1 after previous increment
global
keyword is used inside a function for a variable that is not defined in the global scope?
What will happen if If global
keyword is used for a variable that hasn’t been defined globally (or at module level with global
keyword), Python will create that variable in the global
scope. Python won’t raise an error.
We need to be very careful, while defining a global
variable from inside the function is very risky and can lead to unexpected behavior in your code. Also use the proper comments in code for this usage of global
keyword.
def create_global():
global x # variable x defined in function but with global keyword
x = 100 # Assigns value to a global variable 'x'
create_global()
print(x) # Output: 100 from the global variable 'x'
How do Python closures relate to variable scope?
A closure in Python occurs when a nested function remembers the environment in which it was created, including variables from the enclosing scope, even after the outer function has finished executing. This is closely related to variable scope because closures allow the nested function to access variables from its enclosing scope, demonstrating the importance of the enclosing scope in the LEGB rule.
def outer_function(msg):
def inner_function():
print(msg) # 'msg' is from the enclosing scope
return inner_function
closure_function = outer_function("Hello, World!")
closure_function() # Output: Hello, World!
In this example program, outer_function(msg)
returns an object of inner_function
which prints the value of argument msg
. We called the outer_function("Hello, World!")
. msg
is remembered by inner_function
even after outer_function
has finished executing. This is because of closure.
Related Topics
- Introduction to Variables in Python & Variable Data TypesWhat are Variables in Python In Python, variables act as references to reserved memory locations where actual values are stored. Each variable name points to a specific memory address that holds the assigned value. In this case: How Variable Memory Works When we define variables, like height = 175, Python allocates a specific memory location…
- Understanding Number Datatype in Python: Decimal, Octal and Hexadecimal NumbersUnderstanding the Number Datatype in Python: A Comprehensive Overview Number datatype in Python is a combination of different number format classes like Integer, Float, and Complex. Python supports the Decimal, Octal decimal, and Hexadecimal number systems. Program – Integer Number datatype Output of the Integer Number datatype program: Note from the output: Exploring Float Number…
- Understanding Scope in Python Programming (with Example Programs)In previous articles, we learned about following topics: Understanding Scope in Programming Generally, in the scope of a program, a variable can be declared only once with the same name. But, it’s possible to declare variables with the same name in different scopes within the same program. Changing the value of a variable within a…
- Understanding Lists in Python: A Comprehensive GuideLists in Python List is a core datatype in Python. Lists are sequences used to store elements (collection of data). Lists are similar to Arrays but are of dynamic size. It means the size of the list can be increased or decreased as we add or remove elements from the list. Understanding Python Lists: A…
- How to Create List in Python | Python List Creation Methods ExplainedList is a sequence data type used to store elements (collection of data). Lists are similar to Arrays but have a dynamic size, meaning the list size can increase or decrease as elements are added or removed. A list is a core data type in Python, along with Tuple, Set and Dictionary. Lists in Python…