How to Prevent Naming Collisions When Inheriting Classes?

Let’s assume that we have a prebuilt, imported class named Account that models a bank account. We know only its documentation and public attributes, but we do not know anything about its internal implementation.

To create an instance of the class, you must pass an account number and the maximum amount that can be withdrawn in a single transaction to the constructor. The instance exposes three methods that allow us to deposit money, withdraw money, and retrieve the current balance.

What we want to do is to create a class called CreditAccount, which models a credit account, by inheriting from the Account class. When instantiating CreditAccount, we must provide the account number and the annual credit limit. Since CreditAccount inherits from Account, we also need to determine the maximum amount that can be withdrawn from the credit account when calling the __init__ method of the Account class. We decide that the maximum amount allowed for a single withdrawal will always be one-twelfth of the annual credit limit. During the initialization of CreditAccount, we store the currently available credit amount in a private attribute so that it can later be retrieved through a method defined in the class. We name this private variable so that it reflects the nature of the stored value. For this reason, we name it _limit.

In the following code snippet, you can see the definition of the CreditAccount class along with the result of a test run. You can observe that the result is incorrect because, even though we specified a maximum withdrawal amount, it was still possible to withdraw more money than permitted. Identifying the cause of the error would be quite difficult without knowing the source code of the parent class. For this reason, we have shown the definition of the Account class, too.

After some investigation, we may realize that the issue is caused by a naming conflict as both classes contain an attribute named _limit. The problem is that, in the CreditAccount class, we unintentionally overrode the _limit attribute inherited from the parent class, even though it was intended to store a different kind of value.

Accidental overriding like this can occur in any inheritance hierarchy, which is why Python provides language-level solutions for such situations. To avoid naming conflicts like the one shown in the example, Python offers the so-called name mangling mechanism. Despite its somewhat unusual name, the idea behind it is fairly straightforward.

If an attribute name in the source code starts with at least two underscore characters and ends with at most one underscore character, the interpreter transforms the name during compilation by prepending the class name to it, preceded by a single underscore. The transformed name is what ultimately gets stored in the __dict__ container of the class or instance.

The purpose of this mechanism is that, after compilation, the original attribute name used in the source code can no longer be accessed directly from outside the class because, behind the scenes, it has been transformed into a far more unique name.

Therefore, when designing a class intended to serve as a base class, it is worth considering prefixing attribute names with two underscores if those attributes should neither be used nor overridden by subclasses. In this case, accidental overriding in subclasses will not occur.

Below you can see the modified version of the two classes. The only change is that, instead of using a single underscore in the name _limit, both classes now use a double underscore: __limit. The test results clearly show that the program now behaves correctly. In the last line of the output, you can also see what the name __limit has been converted to in the CreditAccount and Account classes.

As in many cases, the saying “there is no such thing as a free lunch” also applies here. Although this mechanism may seem useful, it does have limitations and drawbacks. You can read more about these in the chapter “Don’t Touch, It’s Not Yours! – Making Attributes Private” in the e-book Python Knowledge Building Step by Step From the Basics to Your First Desktop Application.

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