Python extending with - using super() Python 3 vs Python 2
Solution 1
-
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)
Solution 2
In a single inheritance case (when you subclass one class only), your new class inherits methods of the base class. This includes __init__
. So if you don't define it in your class, you will get the one from the base.
Things start being complicated if you introduce multiple inheritance (subclassing more than one class at a time). This is because if more than one base class has __init__
, your class will inherit the first one only.
In such cases, you should really use super
if you can, I'll explain why. But not always you can. The problem is that all your base classes must also use it (and their base classes as well -- the whole tree).
If that is the case, then this will also work correctly (in Python 3 but you could rework it into Python 2 -- it also has super
):
class A:
def __init__(self):
print('A')
super().__init__()
class B:
def __init__(self):
print('B')
super().__init__()
class C(A, B):
pass
C()
#prints:
#A
#B
Notice how both base classes use super
even though they don't have their own base classes.
What super
does is: it calls the method from the next class in MRO (method resolution order). The MRO for C
is: (C, A, B, object)
. You can print C.__mro__
to see it.
So, C
inherits __init__
from A
and super
in A.__init__
calls B.__init__
(B
follows A
in MRO).
So by doing nothing in C
, you end up calling both, which is what you want.
Now if you were not using super
, you would end up inheriting A.__init__
(as before) but this time there's nothing that would call B.__init__
for you.
class A:
def __init__(self):
print('A')
class B:
def __init__(self):
print('B')
class C(A, B):
pass
C()
#prints:
#A
To fix that you have to define C.__init__
:
class C(A, B):
def __init__(self):
A.__init__(self)
B.__init__(self)
The problem with that is that in more complicated MI trees, __init__
methods of some classes may end up being called more than once whereas super/MRO guarantee that they're called just once.
Solution 3
In short, they are equivalent. Let's have a history view:
(1) at first, the function looks like this.
class MySubClass(MySuperClass):
def __init__(self):
MySuperClass.__init__(self)
(2) to make code more abstract (and more portable). A common method to get Super-Class is invented like:
super(<class>, <instance>)
And init function can be:
class MySubClassBetter(MySuperClass):
def __init__(self):
super(MySubClassBetter, self).__init__()
However requiring an explicit passing of both the class and instance break the DRY (Don't Repeat Yourself) rule a bit.
(3) in V3. It is more smart,
super()
is enough in most case. You can refer to http://www.python.org/dev/peps/pep-3135/
Solution 4
Just to have a simple and complete example for Python 3, which most people seem to be using now.
class MySuper(object):
def __init__(self,a):
self.a = a
class MySub(MySuper):
def __init__(self,a,b):
self.b = b
super().__init__(a)
my_sub = MySub(42,'chickenman')
print(my_sub.a)
print(my_sub.b)
gives
42
chickenman
Solution 5
Another python3 implementation that involves the use of Abstract classes with super(). You should remember that
super().__init__(name, 10)
has the same effect as
Person.__init__(self, name, 10)
Remember there's a hidden 'self' in super(), So the same object passes on to the superclass init method and the attributes are added to the object that called it.
Hence super()
gets translated to Person
and then if you include the hidden self, you get the above code frag.
from abc import ABCMeta, abstractmethod
class Person(metaclass=ABCMeta):
name = ""
age = 0
def __init__(self, personName, personAge):
self.name = personName
self.age = personAge
@abstractmethod
def showName(self):
pass
@abstractmethod
def showAge(self):
pass
class Man(Person):
def __init__(self, name, height):
self.height = height
# Person.__init__(self, name, 10)
super().__init__(name, 10) # same as Person.__init__(self, name, 10)
# basically used to call the superclass init . This is used incase you want to call subclass init
# and then also call superclass's init.
# Since there's a hidden self in the super's parameters, when it's is called,
# the superclasses attributes are a part of the same object that was sent out in the super() method
def showIdentity(self):
return self.name, self.age, self.height
def showName(self):
pass
def showAge(self):
pass
a = Man("piyush", "179")
print(a.showIdentity())
oz123
I am a Software Engineer usually working as DevOps or Back-End developer. I feel comfortable using various Linux distributions (usually at work I have Debian\Ubuntu\Red Hat\CentOS and even {Open,}SuSE. Whenever I can, I use Gentoo and NetBSD). My tools of choice are Python, Go and C. I wrote a little book about Kubernetes Operators in Python and Go! Take a look at my CLI framework for Python.
Updated on November 25, 2020Comments
-
oz123 over 3 years
Originally I wanted to ask this question, but then I found it was already thought of before...
Googling around I found this example of extending configparser. The following works with Python 3:
$ python3 Python 3.2.3rc2 (default, Mar 21 2012, 06:59:51) [GCC 4.6.3] on linux2 >>> from configparser import SafeConfigParser >>> class AmritaConfigParser(SafeConfigParser): ... def __init__(self): ... super().__init__() ... >>> cfg = AmritaConfigParser()
But not with Python 2:
>>> class AmritaConfigParser(SafeConfigParser): ... def __init__(self): ... super(SafeConfigParser).init() ... >>> cfg = AmritaConfigParser() Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 3, in __init__ TypeError: must be type, not classob
Then I read a little bit on Python New Class vs. Old Class styles (e.g. here. And now I am wondering, I can do:
class MyConfigParser(ConfigParser.ConfigParser): def Write(self, fp): """override the module's original write funcition""" .... def MyWrite(self, fp): """Define new function and inherit all others"""
But, shouldn't I call init? Is this in Python 2 the equivalent:
class AmritaConfigParser(ConfigParser.SafeConfigParser): #def __init__(self): # super().__init__() # Python3 syntax, or rather, new style class syntax ... # # is this the equivalent of the above ? def __init__(self): ConfigParser.SafeConfigParser.__init__(self)
-
akaRem about 12 years
Notice how both base classes use super even though they don't have their own base classes.
They have. In py3k every class subclasses object. -
jpmc26 almost 9 years-1. This answer didn't clarify anything for me. In Python 2,
super(__class__)
givesNameError: global name '__class__' is not defined
, andsuper(self.__class__)
is erroneous as well. You must provide an instance as a second argument, which would suggest you need to dosuper(self.__class__, self)
, but that is wrong. IfClass2
inherits fromClass1
andClass1
callssuper(self.__class__, self).__init__()
,Class1
's__init__
will then call itself when instantiating an instance ofClass2
. -
jpmc26 almost 9 yearsTo clarify a point, I get
TypeError: super() takes at least 1 argument (0 given)
when trying to callsuper(self.__class__)
in Python 2. (Which doesn't make a lot of sense, but it demonstrates how much information is missing from this answer.) -
mata almost 9 years@jpmc26: in python2 you get this error because your trying to call
__init__()
without argument on the unbound super object (which you get by callingsuper(self.__class__)
with only one argument), you need a bound super object then it should work:super(CurrentClass, self).__init__()
. Don't useself.__class__
because that will always refer to the same class when calling a parent and therfore create an infinite loop if that parent also does the same. -
CristiFati almost 6 years
__class__
(member) also exists in Python2. -
mata almost 6 years@CristiFati This isn't about the
__class__
member but about the implicitly created lexical__class__
closure which always refers to the class currently being defined, which doesn't exist in python2. -
dturvene over 4 yearsThis is the answer I was looking for, but didn't know how to ask. The MRO description is good.