Syntax
def outer():\n x = value\n def inner():\n return x\n return innerExamples
Basic Closure
An inner function that 'remembers' a variable from its enclosing function.
def make_greeter(greeting):
def greet(name):
return f"{greeting}, {name}!"
return greet
hello_greeter = make_greeter("Hello")
hey_greeter = make_greeter("Hey")
print(hello_greeter("Fola")) # Hello, Fola!
print(hey_greeter("Zain")) # Hey, Zain!Closure with Persistent State (Counter)
Using a closure to maintain private state between calls, without using a class.
def make_counter():
count = 0
def increment():
nonlocal count # allows modifying the outer variable
count += 1
return count
return increment
counter = make_counter()
print(counter()) # 1
print(counter()) # 2
print(counter()) # 3
another_counter = make_counter()
print(another_counter()) # 1 (completely independent state)Practical Example: Configurable Validators
Using a closure to build reusable, pre-configured validation functions.
def make_range_validator(minimum, maximum):
def validate(value):
return minimum <= value <= maximum
return validate
is_valid_age = make_range_validator(0, 120)
is_valid_percentage = make_range_validator(0, 100)
print(is_valid_age(25)) # True
print(is_valid_percentage(150)) # FalseBest practices
- Use the 'nonlocal' keyword when an inner function needs to modify (not just read) a variable from its enclosing scope
- Use closures for lightweight cases of remembered state (a counter, a configured function) instead of writing a full class when it fits
- Each call to the outer function creates a fresh, independent closure - variables are not shared between separately created closures
- Prefer a class with __call__ over a closure once the amount of internal state or behavior grows beyond one or two variables
At a glance
- Purpose
- Scripting and general-purpose applications
- File extension
- .py
- Runs in
- Python interpreter
- Usually used with
- Python standard library and packages
Specifications & further reading
Related Python documentation
def
The def keyword in Python is used to define functions - reusable blocks of code that perform specific tasks. Functions are fundamental to organizing code, avoiding repetition, and making programs more maintainable. A function can accept inputs (parameters), perform operations, and return outputs. Functions are one of the core building blocks of clean, modular Python code.lambda
A lambda is a small, anonymous, single-expression function, created without the def keyword or a name. Lambdas are restricted to a single expression whose result is automatically returned - they can't contain multiple statements or assignments. They're most useful as short, throwaway functions passed as arguments to other functions like sorted(), map(), and filter().return
The return statement exits a function immediately and optionally sends a value back to the caller. A function can return any type - including multiple values as a tuple - or nothing at all, in which case it implicitly returns None. Once return executes, no further code in the function runs, making it useful for early exits as well as producing a final result.*args and **kwargs
*args and **kwargs let a function accept a variable number of arguments. *args collects any extra positional arguments into a tuple, while **kwargs collects extra keyword arguments into a dictionary. The names 'args' and 'kwargs' are just convention - what matters is the * and ** prefixes. This pattern is common in wrapper functions, decorators, and APIs that need to stay flexible about their inputs.
The def keyword in Python is used to define functions - reusable blocks of code that perform specific tasks. Functions are fundamental to organizing code, avoiding repetition, and making programs more maintainable. A function can accept inputs (parameters), perform operations, and return outputs. Functions are one of the core building blocks of clean, modular Python code.lambda
A lambda is a small, anonymous, single-expression function, created without the def keyword or a name. Lambdas are restricted to a single expression whose result is automatically returned - they can't contain multiple statements or assignments. They're most useful as short, throwaway functions passed as arguments to other functions like sorted(), map(), and filter().return
The return statement exits a function immediately and optionally sends a value back to the caller. A function can return any type - including multiple values as a tuple - or nothing at all, in which case it implicitly returns None. Once return executes, no further code in the function runs, making it useful for early exits as well as producing a final result.*args and **kwargs
*args and **kwargs let a function accept a variable number of arguments. *args collects any extra positional arguments into a tuple, while **kwargs collects extra keyword arguments into a dictionary. The names 'args' and 'kwargs' are just convention - what matters is the * and ** prefixes. This pattern is common in wrapper functions, decorators, and APIs that need to stay flexible about their inputs.