InterviewQAs

Python Scope and Lifetime of Variables

Download as PDF
All questions in this page are included
Preparing…
Download PDF
PSA
Python Scope and Lifetime of Variables

Understanding variable scope in Python is essential for controlling access, avoiding naming conflicts, and maintaining code clarity. Scope defines where a variable can be accessed within a program.

Python uses four levels of scope: local, enclosing, global, and built-in, often remembered by the LEGB rule. Each level determines how Python resolves variable names during execution.

Lifetime of a variable refers to how long it exists in memory. Local variables typically exist only during function execution, whereas global variables persist until the program ends.

Improper handling of variable scope can lead to bugs, such as unintentionally modifying global state or creating variables that shadow others in enclosing scopes. Awareness of scope is crucial in modular code design.

Practical examples, like closures, nested functions, or module-level variables, demonstrate how Python’s scoping rules impact memory usage, debugging, and overall program behavior.

Question 01

Explain the difference between local and global variables in Python and how their lifetimes differ.

EASY

Local variables are declared within a function and can only be accessed inside that function. They are created when the function starts and destroyed when the function exits, which defines their short lifetime.

Global variables, on the other hand, are defined at the module level and are accessible from any function within the same module unless explicitly shadowed. Their lifetime spans the entire runtime of the program.

In practice, local variables are ideal for temporary storage and calculations, while global variables should be used sparingly to share state across functions, avoiding accidental side effects.

Question 02

What is the LEGB rule in Python and how does it affect variable resolution in nested functions?

MEDIUM

LEGB stands for Local, Enclosing, Global, Built-in. It defines the order in which Python searches for variable names.

First, Python looks for a variable in the local scope. If not found, it checks the enclosing functions (for nested functions), then the global module-level scope, and finally the built-in namespace.

In nested functions, this rule allows inner functions to access variables from their enclosing function without declaring them as global, enabling patterns like closures and maintaining state between function calls.

Question 03

Describe a situation where improper scope handling can lead to subtle bugs and how to avoid them.

HARD

A common issue arises when a local variable unintentionally shadows a global variable. For example, modifying a global list inside a function by assigning a new list instead of modifying it in place can lead to unexpected behavior.

Another scenario is using mutable default arguments in functions, which retain state across calls due to the function object persisting in memory. This can produce side effects that are hard to trace.

To avoid such bugs, prefer explicit local variable usage, minimize global state, use immutable default arguments, and consider `nonlocal` or `global` keywords carefully when intentionally modifying outer scopes.

Question 04

Which of the following statements about Python variable lifetimes are correct?

EASY
  • A Local variables exist only while their function is executing.
  • B Global variables are destroyed once a function exits.
  • C Variables in the built-in namespace exist for the program's entire runtime.
  • D Enclosing scope variables in nested functions can persist via closures.

Local variables are created when the function starts and destroyed when it exits, defining their short lifespan.

Built-in variables, like `len` or `range`, are always available for the duration of the program.

Enclosing variables can persist when referenced by inner functions (closures), even after the outer function has finished execution.

Question 05

Select the correct ways to modify a global variable inside a function.

MEDIUM
  • A Declare it using the `global` keyword inside the function and assign a new value.
  • B Directly assign a value without any keyword; Python will automatically use the global variable.
  • C Use `nonlocal` keyword to modify it inside the function.
  • D Modify the contents of a mutable global variable like a list or dictionary without `global`.

Using the `global` keyword tells Python to bind the variable in the global scope rather than creating a new local variable.

Mutable objects like lists or dictionaries can be modified in place without the `global` keyword because the reference remains the same.

Question 06

Which of the following statements about variable shadowing and nonlocal behavior are true?

HARD
  • A A local variable can shadow a global variable without any errors.
  • B The `nonlocal` keyword allows modifying a variable in the nearest enclosing function scope.
  • C `nonlocal` can be used to modify global variables.
  • D Using the same variable name in nested functions can lead to unintentional shadowing.

Local variables naturally take precedence over global variables in their scope, which can shadow globals without error.

`nonlocal` specifically targets variables in enclosing (non-global) scopes, allowing controlled modification.

Reusing variable names in nested functions can create confusion and unintended behavior if not carefully managed.

Question 07

Write a Python function that demonstrates a local variable's lifetime.

EASY

Each time `counter_demo` is called, the local variable `count` is created anew and initialized to 0.

This demonstrates that local variables exist only during the function execution and do not retain state across calls.

# Python

def counter_demo():
    count = 0  # local variable
    count += 1
    print(f'Current count: {count}')

counter_demo()
counter_demo()
Question 08

Demonstrate the use of `nonlocal` to modify an enclosing scope variable.

MEDIUM

`nonlocal` allows the inner function to modify `x` in the outer function scope.

This example illustrates how nested functions can maintain and update state without using globals.

# Python

def outer():
    x = 5
    def inner():
        nonlocal x
        x += 10
        print(f'Inner x: {x}')
    inner()
    print(f'Outer x: {x}')

outer()
Question 09

Show how a closure can preserve the lifetime of a variable after its outer function has finished execution.

HARD

The variable `factor` exists in the enclosing scope of `multiply`. The returned function retains access to it.

Even after `make_multiplier` has finished execution, the closure preserves `factor`, demonstrating how Python can maintain variable lifetime beyond the normal local scope.

# Python

def make_multiplier(factor):
    def multiply(number):
        return number * factor
    return multiply

double = make_multiplier(2)
print(double(5))  # Output: 10
Question 10

Illustrate a subtle bug caused by mutable default arguments and explain the scope/lifetime implications.

HARD

Default arguments are evaluated once at function definition, so the same list object is reused across calls.

This behavior extends the lifetime of the local `my_list` beyond a single function call, which can lead to unexpected accumulation of values.

Understanding variable scope and lifetime helps prevent these subtle bugs by preferring immutable defaults or initializing inside the function.

# Python

def append_item(item, my_list=[]):
    my_list.append(item)
    return my_list

print(append_item(1))  # [1]
print(append_item(2))  # [1, 2] (unexpected)
print(append_item(3))  # [1, 2, 3] (unexpected)
Question 11

Why is relying heavily on global variables considered risky in large Python applications?

MEDIUM

Global variables create hidden dependencies between functions and modules. When one part of the application changes a shared global value, unrelated parts of the system may start behaving differently without any obvious connection.

In production systems, this becomes especially problematic in multithreaded applications, ETL pipelines, and long-running services where multiple execution paths may read or update shared state simultaneously.

A more maintainable approach is to pass data explicitly through function arguments, use configuration objects, or encapsulate state within classes. This makes code easier to test, debug, and scale.

Question 12

How does variable scope behave inside list comprehensions in modern Python versions?

HARD

In Python 3, variables created inside list comprehensions have their own local scope. This behavior differs from Python 2, where comprehension variables leaked into the surrounding scope.

For example, after executing `[x for x in range(5)]`, the variable `x` is not accessible outside the comprehension in Python 3. This design prevents accidental overwriting of existing variables in the outer scope.

This change improved predictability in large applications where developers frequently reuse variable names. It also reduced subtle bugs in loops and nested data transformations.

Question 13

What happens when a variable name matches a built-in function name in Python?

MEDIUM

If a variable uses the same name as a built-in function, the local or global variable shadows the built-in reference. For example, assigning a value to `list` or `str` overrides access to Python’s built-in implementations within that scope.

This often causes confusing runtime errors later in execution. A common example is `list = [1, 2, 3]` followed by `list('abc')`, which raises a `TypeError` because `list` now references a list object instead of the built-in constructor.

Experienced Python developers avoid naming variables after built-ins to maintain readability and prevent debugging issues in shared codebases.

Question 14

Which statements about Python local variables are correct?

EASY
  • A A local variable exists only inside the function where it is declared.
  • B A local variable can automatically overwrite a global variable permanently.
  • C Local variables are recreated every time a function executes.
  • D Two different functions can use the same local variable name without conflict.

Local variables are isolated to the function scope and are created independently during each function invocation.

Different functions maintain separate local namespaces, so reusing variable names across functions is completely safe and common in professional codebases.

Question 15

Which situations require the `nonlocal` keyword?

MEDIUM
  • A Updating a variable inside an enclosing nested function scope.
  • B Reading a global variable inside a function.
  • C Modifying a variable from the immediate outer function.
  • D Creating a new variable in the local scope.

`nonlocal` is specifically designed for nested functions where an inner function needs to update a variable from the enclosing function scope.

It is not required for simply reading variables, and it does not apply to creating new local variables.

Question 16

Which statements about closures in Python are true?

HARD
  • A Closures can preserve variables even after the outer function exits.
  • B Closures are commonly used in decorators and callback implementations.
  • C Variables stored in closures are always immutable.
  • D Closures can reduce reliance on global variables.

Closures retain references to variables from their enclosing scopes, allowing state to persist beyond normal function execution.

They are heavily used in decorators, retry handlers, middleware patterns, and event-driven programming because they provide controlled state retention without global variables.

Question 17

Write code that demonstrates how variable shadowing works between global and local scopes.

MEDIUM

The local variable `status` inside the function shadows the global variable with the same name.

The global value remains unchanged because the assignment inside the function creates a new local binding instead of modifying the global variable.

# Python

status = 'CONNECTED'

def process_data():
    status = 'PROCESSING'
    print(f'Inside function: {status}')

process_data()
print(f'Outside function: {status}')
Question 18

Create a function that uses a closure to maintain an execution counter.

MEDIUM

The inner function retains access to `count` even after the outer function completes execution.

This pattern is useful in API rate tracking, lightweight state management, and metrics collection without introducing global variables.

# Python

def request_counter():
    count = 0

    def increment():
        nonlocal count
        count += 1
        return count

    return increment

counter = request_counter()
print(counter())
print(counter())
print(counter())
Question 19

Demonstrate how Python resolves variables using the LEGB rule.

HARD

Python searches for variables in the order Local, Enclosing, Global, and Built-in.

Inside `inner`, Python finds the local `value` first. After returning to `outer`, the enclosing variable is printed, and finally the global variable is accessed outside both functions.

Understanding LEGB resolution is important when debugging nested business logic or callback-heavy applications.

# Python

value = 'GLOBAL'

def outer():
    value = 'ENCLOSING'

    def inner():
        value = 'LOCAL'
        print(value)

    inner()
    print(value)

outer()
print(value)
Question 20

Write a Python example showing how modifying a mutable global object differs from reassigning it.

HARD

Updating a mutable object like a dictionary modifies the existing object in memory and does not require the `global` keyword.

Reassigning the variable itself creates a new binding, so Python requires `global` to indicate that the module-level variable should be replaced.

This distinction becomes important in shared configuration management, caching layers, and long-running backend services.

# Python

config = {
    'timeout': 30
}

def update_timeout():
    config['timeout'] = 60

update_timeout()
print(config)


def replace_config():
    global config
    config = {
        'timeout': 120
    }

replace_config()
print(config)
Question 21

How does Python handle variable scope inside exception handling blocks?

MEDIUM

Variables created inside a `try` or `except` block remain accessible outside the block because Python does not create a separate scope for exception handling structures.

For example, a variable assigned inside a `try` block can still be used later in the function if execution succeeds. However, developers must ensure the variable was actually assigned before accessing it, otherwise an `UnboundLocalError` may occur.

In production code, this commonly appears in database operations, API calls, or file processing logic where variables initialized inside exception handling paths are later reused.

Question 22

Why can closures sometimes lead to unexpected memory retention in long-running Python applications?

HARD

Closures retain references to variables from their enclosing scopes. If those variables reference large datasets, open connections, or heavy objects, they remain in memory as long as the closure exists.

This can unintentionally increase memory usage in background workers, web applications, or streaming systems where closures are repeatedly generated and stored.

Experienced developers monitor closure usage carefully and avoid capturing unnecessary objects. In performance-sensitive systems, minimizing retained references helps reduce memory pressure and improves garbage collection efficiency.

Question 23

What is variable shadowing and why should developers pay attention to it?

EASY

Variable shadowing occurs when a variable in a narrower scope uses the same name as a variable in an outer scope. The inner variable temporarily hides access to the outer variable.

Although shadowing is legal in Python, it can reduce readability and introduce subtle bugs when developers assume they are modifying one variable but are actually interacting with another.

Using descriptive variable names and limiting deeply nested logic helps reduce accidental shadowing in large codebases.

Question 24

Which statements about Python global variables are correct?

MEDIUM
  • A Global variables are accessible throughout the module unless shadowed.
  • B Using many global variables can make debugging harder.
  • C Global variables automatically become thread-safe in Python.
  • D Functions can read global variables without using the `global` keyword.

Python allows functions to read global variables directly, but modifying them requires explicit declaration with `global`.

Excessive use of globals creates hidden dependencies and makes tracing application state significantly harder in enterprise applications.

Question 25

Which scenarios can cause an `UnboundLocalError` in Python?

HARD
  • A Reading a variable before assigning it in the same function scope.
  • B Accessing a built-in function like `len()`.
  • C Assigning to a global variable without using the `global` keyword.
  • D Using a variable inside a loop.

Python determines variable scope during compilation. If a variable is assigned anywhere inside a function, Python treats it as local throughout that function.

Attempting to read the variable before assignment causes `UnboundLocalError`, even if a global variable with the same name exists.

Question 26

Which statements accurately describe Python built-in scope?

EASY
  • A Built-in scope contains predefined functions like `print()` and `range()`.
  • B Built-in variables are searched before local variables.
  • C A local variable can shadow a built-in name.
  • D Built-in scope is checked only if Python cannot find a variable in local, enclosing, or global scopes.

Built-in scope is the last level in Python’s LEGB lookup sequence.

Developers sometimes accidentally override built-ins like `list` or `str`, which can introduce difficult-to-diagnose runtime issues.

Question 27

Write Python code that triggers an `UnboundLocalError` due to scope resolution.

MEDIUM

Python treats `count` as a local variable because it is assigned within the function.

When `print(count)` executes, the local variable has not yet been initialized, causing `UnboundLocalError`.

This behavior surprises many developers during debugging because the global variable exists but is ignored due to local scope rules.

# Python

count = 100


def update_count():
    print(count)
    count = count + 1

update_count()
Question 28

Demonstrate how variable scope behaves inside a loop.

MEDIUM

Unlike some languages, Python loops do not create a separate scope.

Variables declared inside the loop remain accessible after the loop finishes executing.

This behavior is frequently used in scripts and data processing pipelines, but developers should avoid unintentionally reusing loop variables later in the code.

# Python

for i in range(3):
    message = f'Iteration {i}'

print(message)
print(i)
Question 29

Create an example showing how closures behave differently when capturing loop variables.

HARD

All lambda functions output the same value because closures capture the variable reference, not its value at definition time.

By the time the lambdas execute, the loop has completed and `i` contains the final value.

This issue commonly appears in asynchronous callbacks, scheduling systems, and event handlers where closures are created dynamically.

# Python

functions = []

for i in range(3):
    functions.append(lambda: i)

for func in functions:
    print(func())
Question 30

Write a Python example that safely captures loop variables inside closures.

HARD

Using default arguments stores the current value of `i` during each loop iteration.

Each lambda now maintains its own independent value instead of sharing the same reference.

This technique is widely used in callback registration, asynchronous processing, and dynamic function generation.

# Python

functions = []

for i in range(3):
    functions.append(lambda i=i: i)

for func in functions:
    print(func())