π Python Closures β Functions That Remember Their Environment
Introduction π
A closure in Python is a function that remembers the values from its enclosing scope even after that scope has finished executing. Closures enable powerful programming patterns like data hiding, function factories, and decorators.
Note
π‘ A closure = inner function + free variables + remembered environment.
1. Basic Closure Structure π§±
basic_closure.py
def outer():
msg = "Hello"
def inner():
print(msg) # uses variable from outer function
return inner
fn = outer()
fn() # prints "Hello"β Even though outer() has finished, inner() still remembers msg.
2. How Closures Work Internally π
- Inner function uses variables from outer function.
- Outer function returns the inner function.
- Inner function keeps a reference to the outer function's variables.
3. Checking Closure Variables π¦
closure_vars.py
def make_printer(msg):
def printer():
print(msg)
return printer
p = make_printer("Hello Python")
print(p.__closure__) # contains captured variables4. Closure for Function Factories π
function_factory.py
def power(n):
def calc(x):
return x ** n
return calc
square = power(2)
cube = power(3)
print(square(5)) # 25
print(cube(3)) # 27Note
β Closures allow dynamic creation of functions with preset behavior.
5. Closures for Data Hiding π
closure_data_hiding.py
def secret_counter():
count = 0
def increment():
nonlocal count
count += 1
return count
return increment
counter = secret_counter()
print(counter()) # 1
print(counter()) # 2β count is private β cannot be accessed outside.
6. Using nonlocal with Closures π§
nonlocal lets inner functions modify variables from enclosing scopes.
nonlocal_example.py
def bank_account():
balance = 1000
def deposit(amount):
nonlocal balance
balance += amount
return balance
return deposit
acc = bank_account()
print(acc(200)) # 12007. Closures in Decorators π
Decorators rely heavily on closures.
decorator_closure.py
def log(func):
def wrapper():
print("Calling", func.__name__)
return func()
return wrapper
@log
def greet():
print("Hello")
greet()Note
β
wrapper() remembers func through closure.8. Real-World Example: Authentication π
auth_closure.py
def auth(role):
def decorator(func):
def wrapper():
if role != "admin":
return "Access denied"
return func()
return wrapper
return decorator
@auth("admin")
def dashboard():
return "Welcome Admin"
print(dashboard())9. Real-World Example: Event Counter π’
event_counter.py
def event_counter():
count = 0
def track():
nonlocal count
count += 1
return f"Event triggered {count} times"
return track
event = event_counter()
print(event())
print(event())
print(event())10. When to Use Closures? π―
- When you want to hide data inside functions (encapsulation).
- When creating function factories.
- When writing decorators.
- When you need persistent state without classes.
11. Common Mistakes β οΈ
- Trying to modify outer variables without
nonlocal. - Capturing variables incorrectly in loops.
- Forgetting that closures store references, not snapshots.
closure_loop_pitfall.py
funcs = []
for i in range(3):
funcs.append(lambda: i) # all return 2
print([f() for f in funcs])Note
β Use default arguments or closures carefully to avoid this pitfall.
Conclusion π
>>βClosures allow functions to remember β enabling elegant, powerful, and flexible program design.β β¨
You now fully understand Closures in Python! Want the next topic? Try Modules, OOP (Classes & Objects), Scopes, or Decorators with Parameters. Just tell me! π