Scope in Python

Python Scope – Complete Tutorial

The scope or the variable scope in Python is a part of a program where a certain variable is accessible. A variable scope can be categorized as Local, Enclosing, Global, or Built-in.

This Python Scope tutorial covers types of variable scope in Python, how they work, and how you can access variables from different scopes.

Local scope in Python

Whenever you define a variable within a function, its scope lies ONLY within the function. This type of scope is known as local scope. Local variables are variables that are declared in a local scope. Local variables are not known to the program outside the scope of the code block they are defined in. Calling a local variable outside its scope in Python generates an error the same as a not declared variable.

Let us take the following program as an example:

def print_num():
    a = 10
    print('Number inside the function:', a)
print_num()
print('Number outside the function:', a)

Running the above program outputs:

Number inside the function: 10
Traceback (most recent call last):
  File "/home/hi/Desktop/local.py", line 6, in <module>
    print('Number outside the function:', a)
NameError: name 'a' is not defined

From the program output above, the print statement in the function outputs the variable’s value while trying to print it causes the program to issue an error. The error NameError: name 'a' is not defined indicates the the variable was either not accessible in the scope it is called in, or the variable is not declared.

Enclosing scope in Python

The scope inside a nesting function (a function that has another function inside it) is an enclosing scope. Local scope exists inside an enclosing scope, and variables declared in the enclosing scope can be accessed in the local scope.

Let us take the following program as an example:

def print_num():
     a = 10
     def print_num2():
         b = 2
         print('print_num2:', a)
         print('print_num2:', b)
     print_num2()
     print('print_num:', b)
 print_num()

Running the program above outputs:

print_num2: 10
print_num2: 2
Traceback (most recent call last):
  File "/home/hi/Desktop/enclosing.py", line 9, in 
    print_num()
  File "/home/hi/Desktop/enclosing.py", line 8, in print_num
    print('print_num:', b)
NameError: name 'b' is not defined

From the previous example, both variables a and b are outputted to the screen from the nested function since variable a is in the enclosing scope and can be accessed from the local scope and b is declared and accessed inside the local scope. The third print statement generates an error because we are trying to access a variable inside an enclosing scope outside its scope and has not been declared outside the nested function.

Global scope in Python

Global scope is a scope outside any function. Variables declared here can be accessed by the whole program. They can be accessed both inside and outside functions.

Let us take another code as an example:

x = 10
def printer():
    print(x)
printer()
print(x)

The output is as follows:

10
10

The program above outputs the value of x when it is called both in a local scope (in the function) and global scope. This demonstrates that a global variable is accessible anywhere within the code.

Built-in scope in Python

The built-in scope is the widest of them all. The built-in scope is the scope of variables and keywords in the Python language library. Programs can access variables or keywords in this scope without being declared in the program code.

Keywords are special reserved words used by Python. Examples of keywords include: for, while, if, else, and in

LEGB Rule

LEGB rule is the logic that the Python interpreter follows when executing a program. It stands for Local Enclosing Global Built-in, and the order of their execution is respectively.

Let us take consider the program below:

x = 0
def printer():
    x = 1
    def inner_printer():
        x = 2
        print('inner_printer:', x)
    inner_printer()
    print('printer:', x)
printer()
print('global:', x)

When we run the program, the output is as follows:

inner_printer: 2
printer: 1
global: 0

As we can observe, even though the variable is declared differently in all the scopes, Python always checks the for the variable in the current scope the moves up the ladder. The following chart shows how the Python interpreter checks for variables inside a program:

Python Scope - Scope Inclusion and execution order
Scope Inclusion and execution order

The analogy presented above might sometimes cause problems. Let us take the following scenario as an example:

We want to write a function that modifies a global variable. For example:

h = 'bake bread'
def cake():
    h = 'bake cake'
cake()
print(h)

The program above outputs as follows:

bake bread

Why do u think this happened? There is a simple explanation for this when we set the value of h to ‘bake cake,’ Python created a new local variable named h in the scope of cake(). This does not modify the value of the global variable h. Cases like this are where the global keyword comes in handy.

Global keyword

The global keyword tells Python to use the global variable instead of creating one locally. Using the global keyword, we can now correct Scenario 1 to the way we want it. The following code is the modified version of Scenario 1:

h = 'bake bread'
def cake():
    global h
    h = 'bake cake'
cake()
print(h)

The program above outputs as follows:

bake cake

Now we can finally bake some cake?!!!

Nonlocal keyword

Let us consider another scenario:

We want to change the value of a variable in an enclosing scope. For example:

def outer():
    greet = 'Hi'
    def inner():
        greet = 'Bye'
    inner()
    print(greet)
outer()

The program above outputs as follows:

Hi

Cases like this can be corrected using the nonlocal keyword. The nonlocal keyword causes the variable to refer to the previously bound variable in the closest enclosing scope. In other words, it will prevent the variable from trying to bind locally first and force it to go a level ‘higher up’. Its syntax is the same as the global keyword.

The following code corrects Scenario 2:

def outer():
    greet = 'Hi'
    def inner():
        nonlocal greet
        greet = 'Bye'
    inner()
    print(greet)
outer()

The output is as follows:

Bye

Yay, the program can finally say Bye!!!

Summary

This article covered types of variable scopes in Python, how they work, and how you can access variables from different scopes. In addition, we’ve introduced the LEGB rule, which will help you imagine Python scope boundaries when you’re developing your Python programs.

Similar Posts