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
andAmericanEnglish
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'