Sometimes you really do want to just call the method that is defined by the class and not any method that might be defined by a subclass. this.__class__ does not work in this case because this.__class__ returns the class of the object, not the class that defined the method.
class A():
def __init__(self):
super().__init__()
print('A', self.__class__)
class B(A):
def __init__(self):
super().__init__()
print('B', self.__class__)
class C(B):
def __init__(self):
super().__init__()
print('C', self.__class__)
c = C()
Output:
A <class '__main__.C'>
B <class '__main__.C'>
C <class '__main__.C'>
I actually have a real world example for why calling the class local method is sometimes needed.
I have a TextEditor class that I can used to open, edit and save text files. I have a Workspace class that is like a TextEditor, but it is for editing code. It adds syntax highlighting and code execution. I also have a Brower class that is like a Workspace class. In addition to editing and executing code, it understands classes and inheritance and adds a view for navigating classes and methods.
Each of these classes has a layout method that organizes all the parts inside a view. I call the layout method inside the constructor for the class and this introduces a problem. Workspace defines attributes that are not part of TextEditor. If I create a Workspace, TextEditor.__init__ will call Worspace.layout instead of TextEditor.layout. This will crash when it tries to layout parts that haven't been created yet.
class A():
def __init__(self):
super().__init__()
self.layout()
def layout(self):
print('A layout')
class B(A):
def __init__(self):
super().__init__()
self.layout()
def layout(self):
print('B layout')
class C(B):
def __init__(self):
super().__init__()
self.layout()
def layout(self):
print('C layout')
c = C()
Output:
C layout
C layout
C layout
What I really want to do is call the layout method defined in TextEditor. So instead of calling self.layout() I call TextEditor.layout(self) inside TextEditor.__init__()
class A():
def __init__(self):
super().__init__()
A.layout(self)
def layout(self):
print('A layout')
class B(A):
def __init__(self):
super().__init__()
B.layout(self)
def layout(self):
print('B layout')
class C(B):
def __init__(self):
super().__init__()
C.layout(self)
def layout(self):
print('C layout')
c = C()
Output:
A layout
B layout
C layout
Now you might say "Why not call layout after you create the new instance?
workspace = Workspace()
workspace.layout()
That solves the problem, but it is ugly. If I want a Workspace or a Browser I want it to appear fully formed without having to do any configuration.
The dunder method could also be used. I could define a class attribute that references the local method
class A():
def __init__(self):
super().__init__()
self.__layout()
def layout(self):
print('A layout')
__layout = layout
class B(A):
def __init__(self):
super().__init__()
self.__layout()
def layout(self):
print('B layout')
__layout = layout
class C(B):
def __init__(self):
super().__init__()
self.__layout()
def layout(self):
print('C layout')
__layout = layout
c = C()
Output:
A layout
B layout
C layout
I think the "class.method(self)" approach is clearer than "__method = method".