English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

Python Basic Tutorial

Python Flow Control

Python Functions

Python Data Types

Python File Operations

Python Objects and Classes

Python Date and Time

Advanced Knowledge of Python

Python Reference Manual

Python Closures

In this article, you will learn what a Python closure is, how to define a closure, and the reasons for using a closure.

Non-local variables in nested functions

Before understanding what a closure is, we must first understand what a nested function and a non-local variable are.

A function defined inside another function is called a nested function. Nested functions can access variables in the enclosed scope.

By default in Python, these non-local variables are read-only, and we must explicitly declare them as non-local variables (usingnonlocal keyword)to be modified.

Here is an example of a nested function that accesses non-local variables.

def print_msg(msg):
# This is the outer enclosed function
    def printer():
# This is a nested function
        print(msg)
    printer()
# We execute this function
# Output: Hello
print_msg("Hello")

We can see that the nested function printer() can access the non-local variables of the enclosed functionmsg.

Define closure function

What will happen if the last line of the function print_msg() returns the printer() function instead of calling it in the above example? This means the function definition is as follows.

def print_msg(msg):
# This is the outer enclosed function
    def printer():
# This is a nested function
        print(msg)
    return printer  # This has changed
# Now, let's try to call this function.
# Output: Hello
another = print_msg("Hello")
another()

This is unusual.

The print_msg() function is called with a string, and the function bound to "Hello" returned isAnotherName. When calling another(), although we have completed the execution of the print_msg() function, we still remember the message.

This is a technique that attaches some data ("Hello") to the code.In Pythonis calledClosure.

Even if the variable is out of range or the function itself has been deleted from the current namespace, this value in the enclosed scope will be remembered.

Try running the following command in the Python Shell to see the output.

>>> del print_msg
>>> another()
Hello
>>> print_msg("Hello")
Traceback (most recent call last):
...
NameError: name 'print_msg' is not defined

What are the conditions for closure?

From the above example, we can see that in Python, when a nested function refers to a value in its enclosed scope, we have a closure.

The following points summarize the conditions that must be met to create a closure in Python.

  • We must have a nested function (function inside a function).

  • The nested function must refer to values defined in the enclosed function.

  • The enclosed function must return a nested function.

When to use closure?

So, what is the use of closure?

Closure can avoid using global variables and provide some form of data hiding. It can also provide an object-oriented solution to the problem.

When there are few methods implemented in a class (most of the time just one method), closure can provide another more elegant solution. However, when the number of properties and methods increases, it is best to implement a class.

This is a simple example where closure may be more preferable than defining a class and creating an object.

def make_multiplier_of(n):
    def multiplier(x):
        return x * n
    return multiplier
# 3multiplication
times3 = make_multiplier_of(3)
# 5multiplication
times5 = make_multiplier_of(5)
# Output: 27
print(times3(9))
# Output: 15
print(times5(3))
# Output: 30
print(times5(times3(2))

Python decorators alsoA large number of closures are used.

Finally, it is best to point out that the values enclosed in the closure function can be found.

All function objects have a __closure__ attribute, if it is a closure function, then the attribute returns a tuple of cell objects. Refer to the example above, we know that times3and times5It is a closure function.

>>>  make_multiplier_of.__closure__
>>>  times3__closure__
(<cell at 0x0000000002D155B8: int object at 0x000000001E39B6E0>,)

The cell object has an attribute cell_contents that stores closed values.

>>>  times3__closure__[0].cell_contents
3
>>>  times5__closure__[0].cell_contents
5