[CS Fundamentals] Demystifying Variable Scope: Best Practices and Common Pitfalls with Python

[CS Fundamentals] Demystifying Variable Scope: Best Practices and Common Pitfalls with Python

Introduction

In computer science, it is so important to fully understand a variable scope as you may face many errors without knowing how they work or your program prints an unexpected output. This article will deeply explain about local, global variables, closure, and keywords used for variable scope handling in python.


Local vs. Global

If a variable is assigned in the most outer, it is the gloabl variable, otherwise, it is local.

Example:

a = 10 # global

def foo():
    b = 20 # local

Global

  • Global variables are used for fixed values, such as pi. Pi is always going to be 3.14…..

  • Accessing global variables in local is not recommended

    • For example, using global keyword.

Local

  • Local variables are declared in loop, function, etc.

  • They are to solve a certain logic

  • They no longer exists in the memory after function returns (or finishes)

    • But not in closure.

Same Variable Name

b = 20 # global variable

def bar():
    b = 30 # local variable
    print(b)

bar() # 30
print(b) # 20

In the example, we have two variables with one global and one local scope, and their names are the same. Now, think about why the output of bar() is 30. It’s because python seeks for the local variable first. If there is no local variable, then python seeks for the global variable. Therefore, 30 is correct.

Now, think about why the output of print(b) is 20. print(b) is written in the global scope, so python seeks for the global variable. If there is one, it prints the according value. If not, it outputs an error.

Declaring a local variable with the same name of a global variable is called variable shadowing.


UnboundLocalError

Think about the output of foobar()

c = 40

def foobar():
    c = c + 10 
    print('Ex3 >', c)

foobar()

You may think that foobar() will print 50;however, the output is UnboundLocalError.

Traceback (most recent call last):
  File "", line 44, in <module>
    foobar()
  File "", line 38, in foobar
    c = c + 10 # UnboundLocalError
UnboundLocalError: local variable 'c' referenced before assignment

You CANNOT modify a global variable in local scope.

We are trying to access a variable that is not even declared. Remember that python will seek for local variable first. In the code above, we are printing c, so python finds c in the local scope, but it’s not declared, rather it is doing a caculation.

Global Keyword

If you want to modify it, you can use global keyword:

c = 40

def foobar():
    global c
    c = c + 10 
    print('Ex3 >', c)

foobar()

However, using global is not recommended as it is not good for code maintenace. It does not mean that global keyword is wrong. It can be used when needed.


nonlocal Keyword

Before going into the nonlocal keyword, you must understand closure. You can have a look at my article: [Python] How Closures and Decorators in Python Work Together to Simplify Code

def outer():
    e = 70
    def inner():
        e += 10
        print('Ex5 >', e)
    return inner

in_test = outer()
in_test()
Traceback (most recent call last):
  File "", line 69, in <module>
    in_test()
  File "", line 64, in inner
    e += 10
UnboundLocalError: local variable 'e' referenced before assignment

The error message tells us that e+= 10 got some problems. local variable ‘e’ referenced before assignment, but it seems like we are using a variable that is already assigned a value. What’s wrong?

Just like I explained before, we are trying to access a variable that is not even declared. Remember that python will seek for local variable first.

We can use nonlocal keyword, not global this time because it is using closure.

def outer():
    e = 70
    def inner():
        nonlocal e
        e += 10
        print('Ex5 >', e)
    return inner

in_test = outer()
in_test() # 80

locals() & globals()

locals()

  • Python locals() function returns the dictionary of the current local symbol table. We use it to access the local symbol table in Python.
def func(var):
    x = 10
    def printer():
        print('Ex6 >', "Printer Func Inner")
    print('Func Inner', locals())

func('Hi')

We can check local declarations easily 😊!


globals()

  • In Python, the globals() function is a built-in function that returns a dictionary representing the current global symbol table.

Example:

print(globals())

It returns all the things that are declared in the global scope. Not just variables only, but functions are also there.

As you may see, they are in the dictionary. Which means, a variable is created like this:

test_variable = 100
globals()['test_variable'] = 100

The two lines mean the same thing. We can do something more fun:

for i in range(1, 10):
    for k in range(1, 10):
        globals()[f'plus_{i}_{k}'] = i + k

print(globals())
print(plus_1_2) # we can call them!

Did you find this article valuable?

Support Jay's Dev Blog by becoming a sponsor. Any amount is appreciated!