Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is super() broken in Python-2.x? [closed]

It's often stated that super should be avoided in Python 2. I've found in my use of super in Python 2 that it never acts the way I expect unless I provide all arguments such as the example:

super(ThisClass, self).some_func(*args, **kwargs) 

It seems to me this defeats the purpose of using super(), it's neither more concise, or much better than TheBaseClass.some_func(self, *args, **kwargs). For most purposes method resolution order is a distant fairy tale.

  • Other than the fact that 2.7 is the last major release to Python 2, why does super remain broken in Python 2?
  • How and why has Python 3's super changed? Are there any caveats?
  • When and why should I use super going forward?
like image 787
Matt Joiner Avatar asked Feb 21 '11 13:02

Matt Joiner


People also ask

How does super () work Python?

The super() function in Python makes class inheritance more manageable and extensible. The function returns a temporary object that allows reference to a parent class by the keyword super. The super() function has two major use cases: To avoid the usage of the super (parent) class explicitly.

What does super () return in Python?

super() returns a delegate object to a parent class, so you call the method you want directly on it: super().

What is super __init__?

The “__init__” is a reserved method in python classes. It is known as a constructor in Object-Oriented terminology. This method when called, allows the class to initialize the attributes of the class. Python super() The super() function allows us to avoid using the base class name explicitly.


2 Answers

super() is not broken -- it just should not be considered the standard way of calling a method of the base class. This did not change with Python 3.x. The only thing that changed is that you don't need to pass the arguments self, cls in the standard case that self is the first parameter of the current function and cls is the class currently being defined.

Regarding your question when to actually use super(), my answer would be: hardly ever. I personally try to avoid the kind of multiple inheritance that would make super() useful.

Edit: An example from real life that I once ran into: I had some classes defining a run() method, some of which had base classes. I used super() to call the inherited constructors -- I did not think it mattered because I was using single inheritance only:

class A(object):     def __init__(self, i):         self.i = i     def run(self, value):         return self.i * value  class B(A):     def __init__(self, i, j):         super(B, self).__init__(i)         self.j = j     def run(self, value):         return super(B, self).run(value) + self.j 

Just imagine there were several of these classes, all with individual constructor prototypes, and all with the same interface to run().

Now I wanted to add some additional functionality to all of these classes, say logging. The additional functionality required an additional method to be defined on all these classes, say info(). I did not want to invade the original classes, but rather define a second set of classes inheriting from the original ones, adding the info() method and inheriting from a mix-in providing the actual logging. Now, I could not use super() in the constructor any more, so I used direct calls:

class Logger(object):     def __init__(self, name):         self.name = name     def run_logged(self, value):         print "Running", self.name, "with info", self.info()         return self.run(value)  class BLogged(B, Logger):     def __init__(self, i, j):         B.__init__(self, i, j)         Logger.__init__("B")     def info(self):         return 42 

Here things stop working. The super() call in the base class constructor suddenly calls Logger.__init__(), and BLogged can't do anything about it. There is actually no way to make this work, except for removing the super() call in B itself.

[Another Edit: I don't seem to have made my point, judging from all the comments here and below the other answers. Here is how to make this code work using super():

class A(object):     def __init__(self, i, **kwargs):         super(A, self).__init__(**kwargs)         self.i = i     def run(self, value):         return self.i * value  class B(A):     def __init__(self, j, **kwargs):         super(B, self).__init__(**kwargs)         self.j = j     def run(self, value):         return super(B, self).run(value) + self.j  class Logger(object):     def __init__(self, name, **kwargs):         super(Logger,self).__init__(**kwargs)         self.name = name     def run_logged(self, value):         print "Running", self.name, "with info", self.info()         return self.run(value)  class BLogged(B, Logger):     def __init__(self, **kwargs):         super(BLogged, self).__init__(name="B", **kwargs)     def info(self):         return 42  b = BLogged(i=3, j=4) 

Compare this with the use of explicit superclass calls. You decide which version you prefer.]

This and similar stories are why I think that super() should not be considered the standard way of calling methods of the base class. It does not mean super() is broken.

like image 179
Sven Marnach Avatar answered Sep 19 '22 18:09

Sven Marnach


super() is not broken, in Python 2 or Python 3.

Let's consider the arguments from the blog post:

  • It doesn't do what it sounds like it does.

OK, you may agree or disagree on that, it's pretty subjective. What should it have been called then? super() is a replacement for calling the superclass directly, so the name seems fine to me. It does NOT call the superclass directly, because if that was all it did, it would be pointless, as you could do that anyway. OK, admittedly, that may not be obvious, but the cases where you need super() are generally not obvious. If you need it, you are doing some pretty hairy multiple inheritance. It's not going to be obvious. (Or you are doing a simple mixin, in which case it will be pretty obvious and behave as you expect even if you didn't read the docs).

If you can call the superclass directly, that's probably what you'll end up doing. That's the easy and intuitive way of doing it. super() only comes into play when that doesn't work.

  • It doesn't mesh well with calling the superclass directly.

Yes, because it's designed to solve a problem with doing that. You can call the superclass directly if, and only if, you know exactly what class that is. Which you don't for mixins, for example, or when your class hierarchy is so messed up that you actually are merging two branches (which is the typical example in all examples of using super()).

So as long as every class in your class hierarchy has a well defined place, calling the superclass directly works. If you don't, then it does not work, and in that case you must use super() instead. That's the point of super() that it figures out what the "next superclass" is according to the MRO, without you explicitly having to specify it, because you can't always do that because you don't always know what it is, for example when using mixins.

  • The completely different programming language Dylan, a sort of lisp-thingy, solves this in another way that can't be used in Python because it's very different.

Eh. OK?

  • super() doesn't call your superclass.

Yeah, you said that.

  • Don't mix super() and direct calling.

Yeah, you said that too.

So, there is two arguments against it: 1. The name is bad. 2. You have to use it consistently.

That does not translate to it being "broken" or that it should be "avoided".

like image 21
Lennart Regebro Avatar answered Sep 22 '22 18:09

Lennart Regebro