python closures scope LEGB nonlocal global 2024 Interview Q&A
Prepare for senior technical positions. Click on any question to expand and review details.
Here is Interview Prep Q&A module covering intermediate-level concepts than the Python Closures & Scope materials.
Python Closures & Scope: Interview Prep Q&A
Question: What is the LEGB rule inside Python. How does it dictate variable name resolution?
Answer: The LEGB rule dictates exact sequence Python interpreter follows when resolving variable names, and it stands for:
* Local (L): Python first searches the local scope, which is inside the current function you're working in.
* Enclosing (E): If not found locally, it searches the enclosing scope which is the region inside the outer parent function of a nested function.
* Global (G): Next, it checks a global scope which consists of variables defined at the top level of the script, outside all functions.
* Built-in (B): Finally, it checks Python’s built-in names (like print, len, or Exception).
If Python searches through all four of these layers and still can't find the variable name it'll crash and throw the NameError.
Question: How would you explain what a "closure" is to a junior developer, and what's its primary mechanism? Answer: A closure is really essentially a nested function that carries an "invisible backpack" of data. When a child function is created inside parent function it can probably capture and save variables from parent's local scope (the enclosing scope). The defining mechanism of a closure is that even after a parent function finishes executing and its local variables are normally destroyed by Python to save memory the inner child function retains access to those captured variables.
def financial_account(initial_balance):
balance = initial_balance # Enclosing variable
def get_balance():
return balance # The child function packs 'balance' in its backpack
return get_balance
my_account = financial_account(100)
# The parent function is done, but the closure still remembers the balance:
print(my_account()) # Outputs: 100
Question: You're basically writing nested function to process financial transaction and need to update a balance variable defined in the outer function, while however when you write balance = balance - amount inside the inner function, Python throws an error stating local variable is referenced before assignment; why does actually this happen, and how do you fix it?
Answer: This happens because, by default, when you attempt to assign or modify variable inside function, Python assumes you're basically trying for create a brand-new variable into the Local scope, and since local balance hasn't been assigned a value yet, it panics when you try to subtract an amount from it.
For fix this you must use the nonlocal keyword. This explicitly tells the Python interpreter not towards create the new local variable. Instead to reach up into the Enclosing scope and modify the variable saved inside the closure.
def financial_account(initial_balance):
balance = initial_balance
def withdraw(amount):
nonlocal balance # Tells Python to modify the enclosing variable
balance = balance - amount
return balance
return withdraw
Question: From the architectural standpoint, when would you choose to use a closure instead of building fully-fledged Object-Oriented class (like a BankAccount object)?
Answer: You should use a closure when you need a lightweight, fast solution that only requires one or two methods, while building a massive class of __init__, self, and multiple dunder methods is overkill of simple state retention. Closures are also slightly faster and offer absolute data privacy—variables trapped in a closure's enclosing scope can't be accessed or modified directly from a global scope, making them perfectly secure. Conversely, if your data needs to interact with a bunch of different methods or inform the broader structural blueprint of your application, an OOP class is probably the better choice.
Question: What's the major risk or potential pitfall of overusing closures, especially when dealing with large datasets or system resources? Answer: primary risk of overusing closures is causing memory leaks. Because a child function "remembers" its enclosing environment, it forces the objects within that environment to stay alive in your computer's memory. If you trap massive amounts of data inside a closure's backpack—such as huge server logs database connections, or large object-oriented filesystem paths—the Python garbage collector can't clean them up, while over time, this trapped data will consume system memory and can eventually degrade application performance or crash the server.