Python gotchas

By Niraj Zade  |  2023 Sep 17  |  5m read


Variable scope "leakage"

Compared to most other languages, python's variable scopes are very weird. If you are coming from other languages like java, c#, c++ etc, then this is going to lead to unintentional bugs.

Introduction

Does the following program throw an error? Or does it print hello?

if True:
    var = "hello"
if True:
    print(var)

The answer is: It prints hello.

If this caught you by surprise, then this note is for you. If you are coming from other languages like java, c#, c++ etc, then this is something that is different in python. It can trip you up especially if you're a polygot.

There are 2 major reasons why polygots cause bugs in python projects:

  1. Not understanding scope of variables in python
  2. Not understanding the python assignment model

This article focuses on point 1 - Not understanding scope of variables in python.


You don't need to declare variable in the outer scope before setting its value or accessing it:

is_available = None # no need to decalre the variable here
if(<your condition>):
    is_available = True
else:
    is_available = False

print(is_available)

Instead, you can just do this:

if(<your_condition>):
    is_available = True
else:
    is_available = False

print(is_available) # variable is still accessible here!

In python, the variables "leak" into the outer scopes.

Note: for mutual sanity, I recommend declaring variable first in the outermost possible scope, before you go ahead and use it. Keeps things easier to reason with.

Explanation

We can put it in one line:

**Variables are scoped to the nearest function, class, module.

In this exact order.**

Now, again let's look at an example. What's the output of the program below?

def fn():
    if True:
        variable_in_if =1234
        print("Value inside if is:", variable_in_if)
    # still accessible, outside the if
    print("Value outside if is:", variable_in_if)

fn()

Again, coming from other languages, you may expect the output to be:

Value inside if is: 1234
Value outside if is: None (or maybe some error at this live)

But in python, the actual output is:

Value inside if is: 1234
Value outside if is: 1234

The variable_in_if is accessible outside the if also, as if it leaked out.

Now we know for sure - variables "leak" out in python. This isn't an anomaly. This is a normal behaviour in python.

The question you should be asking is: To what extent does a variable leak? What is the scope of this leak?

Answer - Variables are scoped to the nearest function, class, module. In this exact order.

In the above example, the variable_in_if was scoped to the nearest function, which was example_function(). So once it got declared and assigned a value, it became accessible from everywhere throughout the function.


Here is another example. This time, the if that declares the variable is nested inside another if:

def example_function():
    if True:
        if True: # nested if
            var = "hello"
    print(var) # var is still accissible outside the nested if

example_function() # prints hello

The scope of the variable var was set to the nearest function - example_function(). It is accessible throughout the function. Doesn't matter how much nesting is done, the variable will leak into the scope of example_function().

Examples to drill it down

Scope within a function

def outer_function():
    variable_of_outer_function = 1234
    def inner_function():
        print(variable_of_outer_function)
        return
    return

Here, variable_of_outer_function is scoped to the nearest function, which is outer_function. So it is available everywhere inside the outer function. So it is also accessible inside inner_function().

Scope in nested functions

def outer_function():
    def inner_function():
        variable_of_inner_function = 1234
        return
        print(variable_of_inner_function) # accessible within inner_function
    print(variable_of_inner_function) # NOT accessible in outer_function
    return

Here, variable_of_inner_function is scoped to the nearest parent function inner_function. So it is not accessible to the print statement of outer_function.

Global vs local scope collision

variable = 1234
def the_function():
  variable = 6789
  print(variable)

In this case there is a global variable and a local variable within the function.

Here, python treats these two as different variables, and preserves the value of both of the. The local variable does not override the value of the global variable.

So, when python tries to fetch the value of variable to print(), it gets 2 possible values: global and local. In this case, python will: Look for the variable in the current scope. If variable isn't found in current scope, it will go one scope higher and look for the variable. It will keep going higher and higher in scope until it finds a variable of the same name.

If it finds the variable, it will print that value. If it doesn't find any variable, it will raise an exception.

In this case, python is finding value for the print() in the function's local scope, and will find variable right there in the function's local scope. So it will use that local scope value and print 6789 . It didn't have to go up to a higher scope to find the variable.

In this example below, it won't find variable in the function's scope. So it will go up and find variable in the global scope. So python will print 1234, which is the global scope's variable's value.

variable = 1234
def the_function():
  print(variable)

Other Articles

© Niraj Zade 2025 - Website, Linkedin
Website was autogenerated on 2025-11-11
Whoever owns storage, owns computing | Silicon is this generation's atomics