Python super method and call alternatives

I see examples everywhere that superclass methods should be called:

super(SuperClass, instance).method(args) 

Is there a disadvantage:

 SuperClass.method(instance, args) 
+48
python super class
Feb 17 '11 at 19:58
source share
2 answers

Consider the following situation:

 class A(object): def __init__(self): print('Running A.__init__') super(A,self).__init__() class B(A): def __init__(self): print('Running B.__init__') # super(B,self).__init__() A.__init__(self) class C(A): def __init__(self): print('Running C.__init__') super(C,self).__init__() class D(B,C): def __init__(self): print('Running D.__init__') super(D,self).__init__() foo=D() 

So, classes form the so-called inheritance diamond:

  A / \ BC \ / D 

Running code gives

 Running D.__init__ Running B.__init__ Running A.__init__ 

This is bad because C __init__ skipped. The reason for this is because B __init__ calls A __init__ directly.

The purpose of super is to allow diamonds of inheritance . If you do not comment

 # super(B,self).__init__() 

and comment

 A.__init__(self) 

the code gives a more desirable result:

 Running D.__init__ Running B.__init__ Running C.__init__ Running A.__init__ 

Now all __init__ methods are called. Note that while you are defining B.__init__ , you might think that super(B,self).__init__() same as calling A.__init__(self) , but you are mistaken. In the situation above, super(B,self).__init__() actually calls C.__init__(self) .

Saints smokes, B knows nothing about C , and yet super(B,self) knows to call C __init__ ? The reason is that self.__class__.mro() contains C In other words, self (or higher, foo ) knows about C

Therefore, be careful - they are not interchangeable. They can give completely different results.

Using super has pitfalls. It requires a significant level of coordination between all classes of the inheritance diagram. (They should, for example, have the same call signature for __init__ , since any particular __init__ did not know which other __init__ super could call the next, or else use **kwargs .) In addition, you must be compatible using super everywhere. Skip it once (as in the example above) and you will defeat the goal of the super target. See Link for other pitfalls.

If you have full control over the class hierarchy or you avoid diamonds of inheritance, then there is no need for super .

+96
Feb 17 '11 at 20:46
source share
— -

There is no penalty as it is, although your example is somewhat wrong. In the first example, it should be

 super(SubClass, instance).method(args) # Sub, not SuperClass 

and this leads me to citing Python Docs :

There are two typical use cases for super . In a class hierarchy with a single inheritance, super can be used to indicate parent classes without explicitly specifying them, which makes the code more convenient for maintenance. This usage closely matches the use of super in other programming languages.

A second use case is to support shared multiple inheritance in a dynamic runtime environment. This use case is unique to Python and is not found in statically compiled languages ​​or languages ​​that support only one inheritance. This allows you to implement "diamond diagrams", where several base classes implement the same method. Good design dictates that this method has the same call signature in each case (since the order of the calls is determined at run time, because this order adapts to changes in the class hierarchy and because this order can include sibling classes, unknown until runtime).

Basically, using the first method, you don’t need to hard code your parent class for hierarchical classes of one class, and you just can’t do what you want (efficiently / effectively) using the second method when using multiple inheritance.

+7
Feb 17 '11 at 20:13
source share



All Articles