Scope of Variable in Python

Challenge Inside! : Find out where you stand! Try quiz, solve problems & win rewards!

Video Tutorial

Scope of a Variable

Overview

The scope of Variables in Python is defined as “the extent of the area or subject matter that something deals with or to which it is relevant”. In the coding world, this definition remains the same as well for variables. Generally, a variable is valid only in the block it is created in and is called its scope. The variable ‘scope’ is a very fundamental concept in programming. Every developer is aware of the variable’s local and global scope, irrespective of their working language. Most commonly, developers are aware of two general scopes:

  1. Global: The name defined in this scope are accessible to all your code
  2. Local: The name defined in this scope is accessible to only the block it was declared in. i.e. in its local block. However, things are a bit different when it comes to Python.

Introduction

Before understanding what is scopes in Python, we need to familiarize ourselves with namespaces and how they differ from scopes. Let’s briefly discuss them:

According to Python’s official documentation:

  • Namespace determines which identifiers (variables, classes, functions, etc) are available for use.
  • A Scope is a textual region of a Python program where a namespace is directly accessible.

Let’s dig a little deeper:

When you declare a variable, python tracks its ‘name’ and ‘value’ by creating an object and adding this object to an internal dictionary. This internal dictionary serves as a lookup mechanism for Python. When you try to access a variable, the Python interpreter looks at its name in this internal dictionary and returns its value if found. If not found, it returns an error.

Hence, this dictionary’s objects are exactly what namespaces are.

But, while a Python program is running, multiple namespaces exist at that point. Out of these namespaces, the specific namespaces you’ll have access to are determined by the scope you’re inside of.

Hence going back to the scope’s definition according to Python’s official documentation:

“A Scope is a textual region of a Python program where a namespace is directly accessible”

In simple language, the scope is the area in a program that decides what specific namespaces (out of all the multiple existing namespaces in that given time) you’ll have access to.

Types of Scope in Python & the LEGB Rule

  • Turns out, there are four types of scope in Python: LEGB => Local-Enclosed-Global-BuiltIn, and the LEGB rule defines the order of scope in which the interpreter looks into for retrieving the variable name & value from

  • In Python, when you try to read a variable, the Python interpreter will retrieve the corresponding variable by looking up sequentially in the order of LEGB scopes, i.e. the first occurrence of this variable found in any of the scopes starting sequentially from, Local -> Enclosed -> Global -> BuiltIn, will be returned Python Functions Scope Let’s understand what each scope in Python is. Note: each scope in the LEGB sequence is less specific than the previous one.

  • Local Scope: local scope in Python is determined by where the variable has been defined. For example: if the variable has been defined inside a function, then its local scope would be defined as that function’s block only, whereas if the variable has been defined on the top level, then it will be considered under Global Scope (explained below)

Example 1 –

Output:

As b was never defined on the top-level (global), it is only accessible to the local scope of ‘func()’. It returns an error when accessed outside the scope where it was never defined

  • Enclosed Scope: also known as the non-local scope in Python, can be observed when you nest functions inside other functions. Let’s say a function ‘func1()’ has a variable ‘a’ and a nested function ‘func2()’. For this nested function ‘func2()’, ‘a’ is neither global nor local. Hence, the scope of the variable ‘a’ inside ‘func2()’ is what the enclosed scope is, i.e. neither global nor local that’s why it’s also known as the non-local scope

Example 2 –

Output:

  • Thought-1 : But what if in Example-2, we reassign variable ‘a’ as 20 in ‘func2()’? Will its value remain the same in func1()’s scope? Hold on to this thought as we’ll get back to it in a while. Note that ‘func2()’ never existed in its local scope. Hence, according to the LEGB rule, it didn’t find ‘a’ in the L scope but found it in the E scope, i.e. Enclosed Scope*
  • Global Scope: (also known as module scope) When you start writing your code in Python, you’re in the global scope. The main global scope in Python is the namespace it points to when you start writing your Python code. Note: when you define a name at the top of your Python module, then that name is global to that specific module only; that is why it’s also called the module scope in Python

Example 3 –

Output:

  • Thought-2: But what if in Example-3, we reassign variable ‘a’ as 20 in ‘func1()’? Will its value remain the same in global scope? Hold on to this thought as we’ll get back to it in a while. Take note here, variable ‘a’ does not exist in the local scope of ‘func1()’, hence according to the LEGB rule, it doesn’t find ‘a’ in L (of LEGB), not in E (of LEGB), but finds it in ‘G,’ i.e. Global.
  • BuiltIn Scope: When a Python interpreter cannot find a variable in the Local, Enclosed, and Global scope, it finally looks up in the builtIn scope. We are importing ‘pi’ from the math library in the following example. This imported ‘pi’ will belong to the builtIn scope. Note that this identifier shall not be redefined as then it’ll be available for the Python interpreter to be fetched from local, enclosed, or global scope (depending on where it has been redefined)

Example 4 –

Output:

Note: let’s say if pi was redefined as ‘10,’ i.e. ‘pi = 10’ at the global level, then the Python interpreter would always have returned pi as 10. Because now it would’ve been available not at L or E but G i.e. the global scope according to LEGB scope. And hence B, i.e. the BuiltIn scope, would never have been considered.

Getting back to the thoughts we had:

Thought-1: But what if in Example-2, we reassign variable ‘a’ as 20 in ‘func2()’? Will its value remain the same in func1()’s scope?

  • Well, in Example-2, on reassigning variable ‘a’ as 20 in ‘func2()’: Python will create a name and value in its internal dictionary so that ‘a’ will be available for func2’s scope as 20. I.e. it will define ‘a’ in the local scope of ‘ func2()’. That means for ‘func2()’, ‘a’ will exist both in the local scope and enclosed scope, but because Local comes first in sequence in the LEGB order rule, it will fetch the value from ‘a’, defined in this scope.
  • Demonstrating example 2 again with new print statements:

Example 5 –

Output:

  • We observe that on updating ‘a’ to 20, ’a’ is redefined in the local scope of ‘func2()’, and that is what the Python interpreter is reading first for ‘func2()’, whereas the value of ‘a’ remains 10 in func1()’s scope.
  • But what if we want: ‘a’ when updated in ‘func2()’ to be updated in ‘func1()’ scope as well?
  • Here, we’ll introduce the ‘nonlocal’ keyword.

nonlocal Keyword

The ‘nonlocal’ keyword is used to work in scenarios where we have nested functions. Using the nonlocal keyword, we instruct the variable that it should not belong to the inner function. Let’s understand this with an example:

Adding ‘nonlocal’ keyword in Example-5:

Example 6 –

Output:

On comparing the output of Example-5 and Example-6, it’s clearly visible that when the ‘nonlocal’ keyword is added, changes made to ‘a’ in ‘func2()’ are reflected in ‘func1()’ as well. Why is that? Because ‘nonlocal’ instructs ‘a’ that it does not belong to ‘func2()’ but belongs to ‘func1()’. Hence ’a ’ variable’s enclosed scope remains intact in ‘func2()’.

Thought-2: But what if in Example-3, we reassign variable ‘a’ as 20 in ‘func1()’?

  • This situation is similar to what we observed for ‘nonlocal’ keyword.
  • In example 3, if we redefine ‘a’ as 20 in ‘func1()’, then clearly, it will redefine ‘a’ in the local scope of ‘func1()’.
  • Then, according to the LEGB order rule, it will act only on the local scope of ‘a’ in ‘func1()’.
  • Let’s take a look at the example. Adding ‘a = 20’ in ‘func1()’ in Example 3:

Example 7 –

Output –

  • We can observe that on assigning ‘a’ as 20, ‘a’ is redefined in the local scope of ‘func1()’.
  • According to the LEGB rule, even though ‘a’ might exist in the global scope but as ‘a’ also exists in the local scope of ‘func1()’, it will read the value in the local scope.
  • Here, we’ll introduce the ‘global’ keyword.

global Keyword

The Global Keyword is a keyword that allows a user to modify a variable outside of the current scope. It is used inside a function when we want to do assignments or when we want to change the value of a variable. Similar to the ‘nonlocal’ keyword it instructs the variable that it belongs to the global scope and not to any other scope. Take note that ‘nonlocal’ keyword is specific to functions and inner functions only, but to manage the scope of a global variable inside a function, a global keyword has to be used.

Adding ‘global’ keyword in example 7

Example 8

Output –

On comparing the output of Example-7 and Example-8, it’s visible that when the ‘global’ keyword is added, changes made to ‘a’ in ‘func1()’ are reflected globally as now ‘a’ exists in global scope only. Why is that? Because the ‘global’ keyword instructs ‘a’ that it does not belong to any function but exists globally, hence ’a’ variable’s global scope remains intact in ‘func1()’ as well when the ‘global’ keyword is used.

Conclusion

  • LEGB stands for Local-Enclosed-Global-BuiltIn, where these 4 are different types of scope in Python.
  • Local scope in Python of a variable is valid only in the function/block it was defined in.
  • Enclosed scope in Python, also known as the non-local scope of a variable, is valid in cases of nested functions. A variable in the local scope is considered to be in the enclosed scope for a nested function.
  • A variable declared outside of all the functions or at the top level and is accessible to all the blocks and functions is considered to be in Global Scope in Python.
  • A variable that is accessible but not looked up in Local, BuiltIn or Global is considered in BuiltIn Scope in Python.
  • The LEGB rule defines the order of scope in which Python’s interpreter looks up its variables.
  • If we want to change the enclosing variable in an inner function, a nonlocal keyword is required.
  • If we want to change a global variable in a function, a global keyword is required.

Learn More