Python closures
last modified January 29, 2024
Python closures tutorial shows how to use closure functions in Python.
Python functions are first-class citizens. This means that functions have equal status with other objects in Python. Functions can be assigned to variables, stored in collections, created and deleted dynamically, or passed as arguments.
A nested function, also called an inner function, is a function defined inside another function.
#!/usr/bin/python def main(): def build_message(name): msg = f'Hello {name}' return msg name = input("Enter your name: ") msg = build_message(name) print(msg) if __name__ == "__main__": main()
The build_message
is a nested function. It is defined and invoked
inside its outer main
function.
Python closures
A closure is a nested function which has access to a free variable from an enclosing function that has finished its execution. Three characteristics of a Python closure are:
- it is a nested function
- it has access to a free variable in outer scope
- it is returned from the enclosing function
A free variable is a variable that is not bound in the local scope.
In order for closures to work with immutable variables such as numbers and
strings, we have to use the nonlocal
keyword.
Python closures help avoiding the usage of global values and provide some form of data hiding. They are used in Python decorators.
Python simple closure example
The following is a simple example of a Python closure.
#!/usr/bin/python def make_printer(msg): msg = "hi there" def printer(): print(msg) return printer myprinter = make_printer("Hello there") myprinter() myprinter() myprinter()
In the example, we have a make_printer
function, which creates
and returns a function. The nested printer
function is the
closure.
myprinter = make_printer("Hello there")
The make_printer
function returns a printer
function
and assigns it to the myprinter
variable. At this moment, it has
finished its execution. However, the printer
closure still has
access to the msg
variable.
$ ./simple_closure.py hi there hi there hi there
Python closure with nonlocal keyword
The nonlocal
keyword allows us to modify a variable with immutable
type in the outer function scope.
#!/usr/bin/python def make_counter(): count = 0 def inner(): nonlocal count count += 1 return count return inner counter = make_counter() c = counter() print(c) c = counter() print(c) c = counter() print(c)
The example creates a counter function.
def make_counter(): count = 0 def inner(): nonlocal count count += 1 return count return inner
By using the nonlocal
keyword, the count
variable
becomes a free variable. Now we can modify it.
$ ./counter.py 1 2 3
Python closures vs classes
Python closures can be an alternate solution to small classes.
#!/usr/bin/python class Summer(): def __init__(self): self.data = [] def __call__(self, val): self.data.append(val) _sum = sum(self.data) return _sum summer = Summer() s = summer(1) print(s) s = summer(2) print(s) s = summer(3) print(s) s = summer(4) print(s)
We have a Summer
class, which sums values passed to the object.
def __init__(self): self.data = []
The data is kept in the object attribute and is created in the constructor.
def __call__(self, val): self.data.append(val) _sum = sum(self.data) return _sum
Each time the instance is called, the value is appended and the sum is calculated and returned.
The following is an alternate solution with Python closure.
#!/usr/bin/python def make_summer(): data = [] def summer(val): data.append(val) _sum = sum(data) return _sum return summer summer = make_summer() s = summer(1) print(s) s = summer(2) print(s) s = summer(3) print(s) s = summer(4) print(s)
We have the same functionality with a Python closure.
def make_summer(): data = [] def summer(val): data.append(val) _sum = sum(data) return _sum return summer
Because the data
is a list which is mutable, we do not have to
use the nonlocal
keyword.
Source
In this article we have worked with Python closures.
Author
List all Python tutorials.