Ever wondered why there are many methods in Python starting with two underscores that
__look_like_this? What’s the difference between a single, and a double underscore before a method name?
The other day when I was doing my Python assignment, working on my project Tic-Tac-Toe Online in Python, I tried to build a GUI on top of the command-line based client. I thought it would be a better OOP design to create a GUI class that extends the command-line based Client class, and keep the code for the client unchanged. However, I encountered some problems that really puzzled me. – I was unable to override some of the methods in the base class.
Let’s take a look at the following code.
class Base: def test(self): print("Calling __foo()"); self.__foo(); def __foo(self): print("Why is the base class being called?"); class Sub(Base): def __foo(self): print("I'm trying to call this!"); print("This should override the __foo()!!"); a = Sub(); a.test();
I was trying to override the methods defined in the super class. The variable
a is supposedly an instance of
Sub, and the
test() should therefore call the
__foo() on the
Sub class. However, the output of the program was mind-boggling:
Calling __foo() Why is the base class being called?
The first line is easy. Yeah the
test() method from
Base class was being class. However, when the next line
self.__foo() was being executed, why did it call the one in class
Base instead of
Sub? Isn’t this an instance of
This really just didn’t make sense to me. How is it possible that Python doesn’t have method overriding? Obviously Python is an OOP language, but how does inheritance in Python work if I can’t even define a method in a subclass that overrides that in its superclass?
After some quick research, I realized the problem here has to do with the naming conventions in Python. For a scripting language that doesn’t have any access modifier (such as public and private), underscores in method names are actually taken to set the accessibility of the method to facilitate the encapsulation of components.
The following special forms using leading or trailing underscores are recognized (these can generally be combined with any case convention):
_single_leading_underscore: weak “internal use” indicator. E.g.
from M import *does not import objects whose name starts with an underscore.
single_trailing_underscore_: used by convention to avoid conflicts with Python keyword, e.g.
__double_leading_underscore: when naming a class attribute, invokes name mangling (inside class FooBar,
_FooBar__boo; see below).
__double_leading_and_trailing_underscore__: “magic” objects or attributes that live in user-controlled namespaces. E.g.
__file__. Never invent such names; only use them as documented.
Now, everything finally started making sense to me! the double leading underscore
__ actually invokes name mangling so in this example
__foo() would become
_Sub__foo() respectively on each class. Thus, here
_Sub__foo() doesn’t override
Because Python doesn’t really have private methods, the double-underscore are thus reserved as some sort of access modifier so we can use the double-underscore
__ to avoid methods being accidentally overridden by its subclasses and thus to prevent accidental access.
In comparison, the single-underscore
_ doesn’t really control the accessibility of the methods. As the official PEP states, it is just a weak “internal use” indicator. It prevents the methods being imported with
from M import *, but that’s all it does.
__double_leading_and_trailing_underscore__ should be avoided at all times, because they are reserved for Python built-in methods.