Python Extending with - Using Super() Python 3 VS Python 2

Python extending with - using super() Python 3 vs Python 2

  • super() (without arguments) was introduced in Python 3 (along with __class__):

    super() -> same as super(__class__, self)

    so that would be the Python 2 equivalent for new-style classes:

    super(CurrentClass, self)
  • for old-style classes you can always use:

     class Classname(OldStyleParent):
    def __init__(self, *args, **kwargs):
    OldStyleParent.__init__(self, *args, **kwargs)

back compatible call to super() for python2/3

In Python 2, a class must inherit from object in order to be a new-style-class:

class myClass(object):
def __init__(self):

In Python 3, that may or may not be done - it does not make a difference.

Since in your code myClass inherits from myBaseClass, you should make sure that myBaseClass inherits from object:

class myBaseClass(object):
...

class myClass(myBaseClass):
def __init__(self):
super(myClass, self).__init__()

Python 2 & 3 compatibility with `super` and classes who were old-style in Py2 but became new-style in Py3

Yes, it is guaranteed stable across Python versions. The search order is called the Method Resolution Order, or MRO, and this order has been the same since Python 2.3.

For more details on how the order is determined, see the Python 2.3 Method Resolution Order documentation.

You can inspect the MRO by looking at the .__mro__ attribute of a given class; it is a tuple of the classes in method-resolution order.

How does Python's super() work with multiple inheritance?

This is detailed with a reasonable amount of detail by Guido himself in his blog post Method Resolution Order (including two earlier attempts).

In your example, Third() will call First.__init__. Python looks for each attribute in the class's parents as they are listed left to right. In this case, we are looking for __init__. So, if you define

class Third(First, Second):
...

Python will start by looking at First, and, if First doesn't have the attribute, then it will look at Second.

This situation becomes more complex when inheritance starts crossing paths (for example if First inherited from Second). Read the link above for more details, but, in a nutshell, Python will try to maintain the order in which each class appears on the inheritance list, starting with the child class itself.

So, for instance, if you had:

class First(object):
def __init__(self):
print "first"

class Second(First):
def __init__(self):
print "second"

class Third(First):
def __init__(self):
print "third"

class Fourth(Second, Third):
def __init__(self):
super(Fourth, self).__init__()
print "that's it"

the MRO would be [Fourth, Second, Third, First].

By the way: if Python cannot find a coherent method resolution order, it'll raise an exception, instead of falling back to behavior which might surprise the user.

Example of an ambiguous MRO:

class First(object):
def __init__(self):
print "first"

class Second(First):
def __init__(self):
print "second"

class Third(First, Second):
def __init__(self):
print "third"

Should Third's MRO be [First, Second] or [Second, First]? There's no obvious expectation, and Python will raise an error:

TypeError: Error when calling the metaclass bases
Cannot create a consistent method resolution order (MRO) for bases Second, First

Why do the examples above lack super() calls? The point of the examples is to show how the MRO is constructed. They are not intended to print "first\nsecond\third" or whatever. You can – and should, of course, play around with the example, add super() calls, see what happens, and gain a deeper understanding of Python's inheritance model. But my goal here is to keep it simple and show how the MRO is built. And it is built as I explained:

>>> Fourth.__mro__
(<class '__main__.Fourth'>,
<class '__main__.Second'>, <class '__main__.Third'>,
<class '__main__.First'>,
<type 'object'>)

What does 'super' do in Python? - difference between super().__init__() and explicit superclass __init__()

The benefits of super() in single-inheritance are minimal -- mostly, you don't have to hard-code the name of the base class into every method that uses its parent methods.

However, it's almost impossible to use multiple-inheritance without super(). This includes common idioms like mixins, interfaces, abstract classes, etc. This extends to code that later extends yours. If somebody later wanted to write a class that extended Child and a mixin, their code would not work properly.

What is the difference between super() with arguments and without arguments?

In Python-3.x you generally don't need the arguments for super anymore. That's because they are inserted magically (see PEP 3135 -- New Super).

The two argument call and the no-argument call are identical if:

  • The first argument is the class in which the method is defined that uses super. In your case it's Ball so the condition is satisfied.
  • and the second argument to super is the first argument of the method. In your case that's self which is the first argument of the method so that condition is also satisfied.

So in your case there's no difference between the two examples!


However there are some rare cases in which you actually need to call super with different arguments (either with 1 or 2 argument/-s). The documentation of super is a good starting point:

>>> help(super)
Help on class super in module builtins:

class super(object)
| super() -> same as super(__class__, <first argument>)
| super(type) -> unbound super object
| super(type, obj) -> bound super object; requires isinstance(obj, type)
| super(type, type2) -> bound super object; requires issubclass(type2, type)
| Typical use to call a cooperative superclass method:

But I assume your question was mostly about the difference in your example (where there is no difference) and these super calls that require arguments are very rare and quite an advanced topic, so I'll leave them out of this answer.

However there are some resources that might help if you're interested in the differences:

  • Which of the 4 ways to call super() in Python 3 to use?
  • How can I use super() with one argument in python

Understanding Python super() with __init__() methods

super() lets you avoid referring to the base class explicitly, which can be nice. But the main advantage comes with multiple inheritance, where all sorts of fun stuff can happen. See the standard docs on super if you haven't already.

Note that the syntax changed in Python 3.0: you can just say super().__init__() instead of super(ChildB, self).__init__() which IMO is quite a bit nicer. The standard docs also refer to a guide to using super() which is quite explanatory.

How do I properly inherit from a base class using Super() (Python 2/3)?

The simple way to inherit with Python 3 is

class TestService(ServiceMap):

def __init__(self, value=None, **kwargs):
super().__init__(value, kwargs) #equivalent to ServiceMap.__init__(self,value, kwargs)
code_specific to this class()

This gives you a "proper" ServiceMap that you then complement

extending class in python 2.7, usage of super()

Most likely because ConfigParser does not inherit from object, hence, is not a new-style class. That's why super doesn't work there.

Check the ConfigParser definition and verify if it's like this:

class ConfigParser(object): # or inherit from some class who inherit from object

If not, that's the problem.

My advice to your code is not use super. Just invoke directly self on the ConfigParser like this:

class MyParser(ConfigParser):
def __init__(self, cpath):
ConfigParser.__init__(self)
self.configpath = cpath
self.read(self.configpath)

Python super() arguments: why not super(obj)?

The two-argument form is only needed in Python 2. The reason is that self.__class__ always refers to the "leaf" class in the inheritance tree -- that is, the most specific class of the object -- but when you call super you need to tell it which implementation is currently being invoked, so it can invoke the next one in the inheritance tree.

Suppose you have:

class A(object):
def foo(self):
pass

class B(A):
def foo(self):
super(self.__class__, self).foo()

class C(B):
def foo(self):
super(self.__class__, self).foo()

c = C()

Note that c.__class__ is C, always. Now think about what happens if you call c.foo().

When you call super(self.__class__, self) in a method of C, it will be like calling super(C, self), which means "call the version of this method inherited by C". That will call B.foo, which is fine. But when you call super(self.__class__, self) from B, it's still like calling super(C, self), because it's the same self, so self.__class__ is still C. The result is that the call in B will again call B.foo and an infinite recursion occurs.

Of course, what you really want is to be able to call super(classThatDefinedTheImplementationThatIsCurrentlyExecuting, self), and that is effectively what the Python 3 super() does.

In Python 3, you can just do super().foo() and it does the right thing. It's not clear to me what you mean about super(self) being a shortcut. In Python 2, it doesn't work for the reason I described above. In Python 3, it would be a "longcut" because you can just use plain super() instead.

The super(type) and super(type1, type2) uses might still be needed occasionally in Python 3, but those were always more esoteric usages for unusual situations.



Related Topics



Leave a reply



Submit