Can multiple closure functions access the same enclosed local variable?

The short answer is yes. The real question is how.

The reason why this topic is interesting is that when we talk about closures, we usually think of a single function nested inside an enclosing function. This inner function becomes the return value of the enclosing function and, when called later, still has access to the enclosing function’s local variables.

However, there is nothing preventing us from defining not just one, but multiple functions within the enclosing function. In such cases, the enclosing function returns not just a single function, but a sequence of nested functions, and are most often passed to the caller as a tuple.

To make this clearer, let’s look at an example.

Suppose we want to model a simple bank account system. To do this, we need to be able to open an account with a unique account number, deposit a given amount, withdraw an amount (if the balance allows), and check the balance. This requires implementing four operations: opening an account, depositing, withdrawing, and checking the balance.

As is usually the case, there are several ways to solve this problem. Typically, we would define a class with methods for opening an account, depositing, withdrawing, and checking the balance. The bank account data (account number and current balance) is stored in a data attribute that references an appropriate container.

Here, however, we take a different approach and implement the operations using closure functions nested inside a single enclosing function. Since these closure functions are defined within the same enclosing function, they all have access to the dictionary created as a local variable of the enclosing function, which maps account numbers to balances.

The function definition and its usage are shown below, with the latter presented in two ways. In the first case, the four closure functions are assigned to separate variables. In the second version, since the functions are logically related, they are implemented as attributes of a namedtuple. The results are, of course, the same in both cases given the same input.

In this solution, the dictionary holding the account data is completely safe: it cannot be modified or overwritten from outside, not even accidentally. In contrast, this would not be the case if we had used the custom class-based approach, since in Python even variables intended to be private can still be accessed if their names are known.

Despite these advantages, closure-based solutions like this are not very common in everyday practice, for several reasons. On the one hand, the way closures work is not immediately intuitive to everyone. On the other hand, the object-oriented paradigm, with its class-based approach, is by far the most common. Another practical consideration is that if you need to create many objects rather than just a few, a class-based solution may be more appropriate.

But we presented this approach to illustrate that in Python, a wide range of problems can be solved using regular, nested, and closure functions without defining classes. The versatility of functions is why the e-book Python Knowledge Building Step by Step covers functions and their variations in great detail, and only after these chapters—building on that foundation—introduces class definitions and object instantiation and all related topics.

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