Since there is a valid use-case for class-private members (namely to avoid name clashes of names with names defined by subclasses), there is limited support for such a mechanism, called name mangling. Any identifier of the form __spam (at least two leading underscores, at most one trailing underscore) is textually replaced with _classname__spam, where classname is the current class name with leading underscore(s) stripped. This mangling is done without regard to the syntactic position of the identifier, as long as it occurs within the definition of a class.
Mangling the name of a parent class method parent.__m(a, b)
to allow a child to overload it with extra parameters child.m(a, b, c)
. This way when you call child.m(1, 2, 3)
, the extra parameter isn't being passed to the parent class and confusing it.
Mangling isn't necessary if you plan on keeping the same method signature but changing some of the internal functionality. You can still access the old functionality by using super()
.
In summary if you want the ability to overload a class method in the future, mangle it. Otherwise, it's not necessary.
Is my summary correct? The docs are poorly written. Lots of run-on sentences and midstream (asides) that muddle my ability to determine if I've understood correctly.
Edit: I just played with some code:
class Parent( object ):
def __init__(self, a, b):
self.a = a
self.b = b
def method( self ):
return 1
class Child(Parent):
def __init__(self, a, b, c ):
super().__init__(a, b)
def method(self, c):
field = [c]
return field
a, b, c = 0, 1, 2
c = Child(a, b, c)
print(c)
This works well enough. The only issue I ran into is if I do something like this:
class Parent( object ):
def __init__(self, a, b):
self.a = a
self.b = b
self.c = self.method()
def method( self ):
return 1
class Child(Parent):
def __init__(self, a, b, c ):
super().__init__(a, b)
self.c = self.method(c)
def method(self, c):
field = [c]
return field
a, b, c = 0, 1, 2
c = Child(a, b, c)
Which returns
TypeError: method() missing 1 required positional argument: 'c'
This is discussed in this answer: Python, Overriding an inherited class method
So at the end of the day it looks like I still don't understand what the purpose is.
Name mangling is unnecessary for a child class to override a method with more parameters. The purpose is to prevent overriding of a method, particularly the overriding of a "private" method that serves some internal purpose for the class and whose behaviour should not be changed by subclasses.
The idea is that if a subclass declares a method of the "same" name, it will be mangled to a different one to avoid overriding the superclass's method. Compare and contrast with Java, where a private
method cannot be overridden or even called from within the subclass.
class A:
def foo(self):
self.bar()
self.__baz()
def bar(self):
print('A.bar')
def __baz(self):
print('A.__baz')
class B(A):
def bar(self):
print('B.bar')
def __baz(self):
print('B.__baz')
B().foo()
Output:
B.bar
A.__baz
Note that this is about overriding, not overloading. Python does not have method overloading, the number or types of the arguments in a method call are not used to determine which method is invoked; only the method name is used for that.