5.4. OOP Name Mangling

  • Is used to avoid name collision in subclasses

  • Does not protect from accessing private methods

  • Allows for accessing superclass methods, even if they were overridden

5.4.1. Syntax

>>> class User:
...     def __login(self):
...         print('ok')

5.4.2. Problem

We have two classes: User and Admin. Both classes have a method login. The User class has a method login that prints User login. The Admin class overrides the method, and it prints Admin login. This could be used to implement different permissions and roles.

>>> class User:
...     def login(self):
...         print('User login')
...
>>> class Admin(User):
...     def login(self):
...         print('Admin login')
...
>>> mark = Admin()

Now, let's call .login() method:

>>> mark.login()
Admin login

How to access a login method from User class?

5.4.3. Solution

Use name mangling to access superclass methods, even if they were overridden

>>> class User:
...     def __login(self):
...         print('User login')
...
>>> class Admin(User):
...     def __login(self):
...         print('Admin login')
...
>>> mark = Admin()

We can access the method by using name mangling:

>>> mark._User__login()
User login
>>> mark._Admin__login()
Admin login

Name mangling allows us to access superclass methods, even if they were overridden by a subclass.

5.4.4. Default

>>> class User:
...     def login(self):
...         print('User login')
...
...     __login = login
>>>
>>>
>>> class Admin(User):
...     def login(self):
...         print('Admin login')
...
...     __login = login

Creating an instance of the User class and calling the login method works as expected:

>>> mark = User()
>>> mark.login()
User login

Similarly, creating an instance of the Admin class and calling the login method works as expected:

>>> mark = Admin()
>>> mark.login()
Admin login

5.4.5. Use Case - 1

  • Name Mangling

  • BritishEnglish and AmericanEnglish classes

Check this simplified example. We have two classes: BritishEnglish and AmericanEnglish. Essentially american english is very similar to british english, but some words are different. Mind that this is only an example. We can model this by creating two classes, where AmericanEnglish is a subclass of BritishEnglish:

>>> class BritishEnglish:
...     def hello(self): return 'Good Morning'
...     def goodbye(self): return 'Goodbye'
...     def thankyou(self): return 'Thank you'
...     def please(self): return 'Please'
...     def sorry(self): return 'Sorry'
...
>>> class AmericanEnglish(BritishEnglish):
...     def hello(self): return 'Hi'
...     def goodbye(self): return 'Bye'

Now, let's create an instance of AmericanEnglish:

>>> lang = AmericanEnglish()
>>>
>>> lang.thankyou()
'Thank you'
>>>
>>> lang.hello()
'Hi'

Calling lang.thankyou() will return Thank you and this behavior was defined in the superclass BritishEnglish. But, calling lang.hello() will return Hi and this is because we have overridden the method in the subclass AmericanEnglish.

Now, let's see how we can access superclass methods even if they were overridden:

>>> lang.__class__.__mro__[1].hello(lang)
'Good Morning'

Or, a bit easier:

>>> super(lang.__class__, lang).hello()
'Good Morning'

This is where name mangling comes into play. Let's define the classes with name mangling:

>>> class BritishEnglish:
...     def hello(self): return 'Good Morning'
...     def goodbye(self): return 'Goodbye'
...     def thankyou(self): return 'Thank you'
...     def please(self): return 'Please'
...     def sorry(self): return 'Sorry'
...     __hello = hello
...     __goodbye = goodbye
...     __thankyou = thankyou
...     __please = please
...     __sorry = sorry
>>>
>>> class AmericanEnglish(BritishEnglish):
...     def hello(self): return 'Hi'
...     def goodbye(self): return 'Bye'
...     __hello = hello
...     __goodbye = goodbye

We create an instance, as it was before:

>>> lang = AmericanEnglish()

All methods works as they were before:

>>> lang.thankyou()
'Thank you'
>>>
>>> lang.hello()
'Hi'

Now, we can access superclass methods by using name mangling:

>>> lang._BritishEnglish__hello()
'Good Morning'
>>> lang._AmericanEnglish__hello()
'Hi'

5.4.6. References

5.4.7. Assignments