What is a closure and what is it used for?

In Python, closures appear in many different use cases. For example, decorators, which are one of the characteristic language constructs in Python, are built on them.

A function that is defined inside another function (the enclosing function) and returned by it is called a closure. Its defining characteristics are not only that it is defined within another function, but also the following:

  • They remain accessible outside the enclosing function, even after it has finished executing.
  • They are “closed over” their defining environment (which is where the name comes from). This means that they retain access to the local variables of the enclosing function, even when the control flow is no longer within that function.

It is as if a closure has its own memory. In other words, it doesn’t matter that the program execution has left the enclosing function—the closure preserves the values of its local variables and can use them every time it is called, regardless of where or how often it is invoked in the program.

To draw an analogy, a closure is like a soldier stationed at a military base: they can be deployed anywhere outside the base, and wherever they go, they carry the equipment provided by the base in their backpack.

Let’s now take a simple illustrative example.

Suppose the task is to continuously track the consumption of tables in a restaurant after each order. The restaurant offers two menus, from which guests can choose—one for weekdays and one for weekends. When guests at a table finish their meal and want to pay, the total amount must be calculated. However, if they ask for the current total during the meal, that should also be available.

This problem can be solved in several ways. In this example, we will use a closure. Below you can see the program’s complete code.

We store the available dishes and their prices in two dictionaries. The function consumption takes one of these dictionaries as an argument. Inside this enclosing function, we define another function called total, which takes the name of the ordered dish as its argument. Based on the selected menu (passed to the enclosing function) and the dish name, we determine the price and store it in a list called prices. The total function returns the current sum of this list. The enclosing function then returns the total function as an object.

Now suppose guests arrive at two tables. We call the consumption function twice, passing in the selected menu. The values of the variables table1 and table2 are closure functions. Orders are placed in the usual stages (appetizer, main course, dessert). Whenever a new dish is ordered, we call the corresponding closure function with name of the dish. Finally, we display the total amounts due.

The advantage of this approach is that it results in clear and flexible code. This means that if new guests arrive at another table, there is no need to modify the existing code—one can simply extend the program by following the same pattern.

This topic is covered in much greater detail in the chapter “Functions That Capture Their Environment – Closures” of the e-book Python Knowledge Building Step by Step from the Basics to the First Desktop Application.

Interested in the e-book Python Knowledge Building Step by Step: From the Basics to Your First Desktop Application?