Super in Python
Article Directory
1. Preface (all content is based on the code from the beginning)
class A:
def __init__(self):
print('A')
class B(A):
def __init__(self):
print('B')
if __main__ == '__main__':
b = B()
# B
But in some cases, we want to be able to directly call the method of its parent class at runtime, how to do it?
class A:
def __init__(self):
print('A')
class B(A):
def __init__(self):
super(B,self).__init__()
# super().__init__()
print('B')
if __main__ == '__main__':
b = B()
# B
# A
In python2
is super(B,self).__init__()
; in python3
is simplified to super().__init__()
.
2. Since the constructor of object B can be rewritten, why call super?
Take multithreading as an example. We define our own thread class MyThread
and then inherit the Thread
class.
from threading import Thread
class MyThread(Thread):
def __init(self,name,user):
self.user = user
# self.name = name (不需要)
super().__init__(name=name)
In the custom MyThread
class, first define an initialization function, assuming that two parameters name
(thread name) and user
(executing user) are passed to it . Can not be used at this time self.name = name
.
Because Thread
the __init__
method has been implemented in the class in the source code, there are many parameters in the method, among which there are name
parameters, and a lot of logic is also implemented in the method.
In fact, let the custom MyThread
class directly call the parent class Thread
, which is equivalent to handing over the constructor to the parent class to instantiate, so that the code (method, logic) in the parent class can be reused, so in some cases, the super
function Still need to call.
Thread
The__init__
part of the class source code (no need to look closely, just pay attention to the structure)
class Thread:
"""A class that represents a thread of control.
This class can be safely subclassed in a limited fashion. There are two ways
to specify the activity: by passing a callable object to the constructor, or
by overriding the run() method in a subclass.
"""
def __init__(self, group=None, target=None, name=None,
args=(), kwargs=None, *, daemon=None):
"""This constructor should always be called with keyword arguments. Arguments are:
*group* should be None; reserved for future extension when a ThreadGroup
class is implemented.
*target* is the callable object to be invoked by the run()
method. Defaults to None, meaning nothing is called.
*name* is the thread name. By default, a unique name is constructed of
the form "Thread-N" where N is a small decimal number.
*args* is the argument tuple for the target invocation. Defaults to ().
*kwargs* is a dictionary of keyword arguments for the target
invocation. Defaults to {}.
If a subclass overrides the constructor, it must make sure to invoke
the base class constructor (Thread.__init__()) before doing anything
else to the thread.
"""
assert group is None, "group argument must be None for now"
if kwargs is None:
kwargs = {
}
self._target = target
self._name = str(name or _newname())
self._args = args
self._kwargs = kwargs
if daemon is not None:
self._daemonic = daemon
else:
self._daemonic = current_thread().daemon
self._ident = None
self._tstate_lock = None
self._started = Event()
self._is_stopped = False
self._initialized = True
# sys.stderr is not stored in the class like
# sys.exc_info since it can be changed between instances
self._stderr = _sys.stderr
# For debugging and _after_fork()
_dangling.add(self)
3. What is the execution order of the super function?
The super function calls the constructor (method) of the parent class. This sentence is actually not completely correct. (This involves MRO
algorithms)
To give a simple example, define 4 classes, B and C both inherit A, and D inherit B and C. If a super
function is used in class D , and the parent class of class D has two (B and C), because B is before C, the constructor in B is called first.
And there are super
functions in B, so should I print A? It can be seen from the running results that the answer is yesNO
.
super
The function is not only calling the parent class function, but also in the order of the MRO
algorithm inheritance chain.
class A:
def __init__(self):
print('A')
class B(A):
def __init__(self):
print('B')
super().__init__()
class C(A):
def __init__(self):
print('C')
super().__init__()
class D(B,C):
def __init__(self):
print('D')
super(D,self).__init__()
if __main__ == '__main__':
d = D()
# D
# B
# A
# C
Use __mro__
to see the order in the inheritance chain-first D, then B, then C, then A.
print(D.__mro__)
# (<class ‘__main__.D’>,<class ‘__main__.B’>,<class ‘__main__.C’>,<class ‘__main__.A’>,<class ‘object’>)