This is probably very simple question. In a child class, which is inherited from two parent classes, I can't access variable from second parent class using super(). Here is my code:
class Core:
def __init__(self):
self.a_from_Core = 7
class Extra:
def __init__(self):
self.b_from_Extra = 90
class Trash(Core, Extra):
def __init__(self):
super().__init__()
print(self.a_from_Core) # working
print(self.b_from_Extra) # does not work
trashcan = Trash()
And here is error:
AttributeError: 'Trash' object has no attribute 'b_from_Extra'
What am I doing wrong?
Python uses "cooperative" multiple inheritance (https://rhettinger.wordpress.com/2011/05/26/super-considered-super/)
which kinda means all classes involved in the inheritance need to agree to play.
For single inheritance, it just works -- which is what lulled you into thinking it would work for multiple.
You need to add calls to super().__init__() in all classes, for example
class Core:
def __init__(self):
self.a_from_Core = 7
super().__init__() # added
class Extra:
def __init__(self):
self.b_from_Extra = 90
super().__init__() # added
class Trash(Core, Extra):
def __init__(self):
super().__init__()
print(self.a_from_Core)
print(self.b_from_Extra) # works!
trashcan = Trash()
You are inheriting from two classes, according to MRO, your first father is Core and your second father is Extra.
So when you call super, the __init__ in Core is called and the __init__ in the Extra is not called, so you don't have b_from_Extra.
As in MRO of Trash you have something like: [..., Core, Extra], if you call super in Core, the method in Extra would be called.
So you can do the following :
class Core:
def __init__(self):
self.a_from_Core = 7
super().__init__()
...
You can read about MRO.
Related
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)
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)
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.
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/
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
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())
Usually super works like the following in Python:
class SubClass(MyParentClass):
def __init__(self):
super(**SubClass**, self).__init__()
But recently I found something like the following also works? No crash, behaviors as expected:
class SubClass(MyParentClass):
def __init__(self):
super(**MyParentClass**, self).__init__()
How come? What does the second case mean?
super(MyParentClass, self).__init__() Will call grandparent class (If it has one)
class BaseClass:
def __init__(self):
print("BaseClass")
class MyParentClass(BaseClass):
def __init__(self):
print("MyParentClass")
class SubClass(MyParentClass):
def __init__(self):
super(SubClass, self).__init__()
class SubClassTwo(MyParentClass):
def __init__(self):
super(MyParentClass, self).__init__()
SubClass() # output: MyParentClass
SubClassTwo() # output: BaseClass
Actually, the behaviour it's not the same.
From the documentation of super() (docs here):
Return a proxy object that delegates method calls to a parent or
sibling class of type.
So if you have:
class MyParentClass:
def __init__(self):
print('MyParentClass.__init__ called!')
class SubClass(MyParentClass):
def __init__(self):
super(MyParentClass, self).__init__()
The call:
super(MyParentClass, self).__init__()
has no effect, because MyParentClass has no parents but object.
If you call:
super(SubClass, self).__init__()
It will print:
MyParentClass.__init__ called!
Because SubClass has one parent, MyParentClass.
The documentation for super says (in part):
super([type[, object-or-type]])
Return a proxy object that delegates method calls to a parent or
sibling class of type. This is useful for accessing inherited methods
that have been overridden in a class. The search order is same as that
used by getattr() except that the type itself is skipped.
So super(MyParentClass, self) resolves to a proxy object that will pass method calls through to the parents and siblings of MyParentClass. It shouldn't be surprising that this works. If your parent class is
class MyParentClass:
def __init__(self, **kwargs):
...
super(MyParentClass, self).__init__(kwargs)
Then when you make a SubClass object, the self in the MyParentClass super call is a SubClass instance.
I'm trying to define self.data inside a class inheriting from a class
class Object():
def __init__(self):
self.data="1234"
class New_Object(Object):
# Code changing self.data here
But I ran into an issue.
class Object():
def __init__(self):
self.data="1234"
So I have the beginning class here, which is imported from elsewhere, and let's say that the class is a universal one so I can't modify the original at all.
In the original, the instance is referred to as "self" inside the class, and it is defined as self inside the definition __init__.
class New_Object(Object):
# Code changing self.data here
So if I wanted to inherit from the class Object, but define self.data inside New_Object, I thought I would have to define __init__ in New_Object, but this overrides the __init__ from New_Object
Is there any way I could do this without copypasting the __init__ from Object?
You use super to call the original implementation.
class New_Object(Object):
def __init__(self):
super(NewObject, self).__init__()
self.info = 'whatever'
That's what super is for:
class NewObject(Object):
def __init__(self):
super(NewObject, self).__init__()
# self.data exists now, and you can modify it if necessary
You can use super().__init__() to call Object.__init__() from New_Object.__init__().
What you would do:
class Object:
def __init__(self):
print("Object init")
self.data = "1234"
class New_Object(Object):
def __init__(self):
print("calling super")
super().__init__()
print("data is now", self.data)
self.data = self.data.split("3")
o = New_Object()
# calling super
# Object init
# data is now 1234
Note that you do not have to give any arguments to super(), as long as you are using Python 3.
The answer is that you call the superclass's __init__ explicitly during the subclass's __init__. This can be done either of two ways:
Object.__init__(self) # requires you to name the superclass explicitly
or
super(NewObject, self).__init__() # requires you to name the subclass explicitly
The latter also requires you to ensure that you're using "new-style" classes: in Python 3 that's always the case, but in Python 2 you must be sure to inherit from the builtin object class. In Python 3 it can actually be expressed even more simply:
super().__init__()
Personally, in most of my code the "disadvantage" of having to name the superclass explicitly is no disadvantage at all, and Object.__init__() lends transparency since it makes it absolutely clear what is being called. This is because most of my code is single-inheritance only. The super route comes into its own when you have multiple inheritance. See What does 'super' do in Python?
Python 2 example:
class Object(object):
def __init__(self):
self.data = "1234"
class NewObject:
def __init__(self):
# subclass-specific stuff
super(NewObject, self).__init__()
# more subclass-specific stuff
I have base class like below
class FileUtil:
def __init__(self):
self.outFileDir = os.path.join(settings.MEDIA_ROOT,'processed')
if not os.path.exists(outFileDir):
os.makedirs(outFileDir)
## other methods of the class
and I am extending this class as below:
class Myfile(FileUtil):
def __init__(self, extension):
super(Myfile, self).__init__()
self.extension = 'text'
## other methods of class
But i am getting below error?
super(Myfile, self).__init__()
TypeError: super() takes at least 1 argument (0 given)
I gone through many documents and found that there are different sytex of calling super() in 2.x and 3.x. I tried both ways but getting error.
You have 2 options
old style class, you should call the super constructor directly.
class FileUtil():
def __init__(self):
pass
class Myfile(FileUtil):
def __init__(self, extension):
FileUtil.__init__(self)
new style class, inherit from object in your base class and your current call to super will be processed correctly.
class FileUtil(object):
def __init__(self):
pass
class Myfile(FileUtil):
def __init__(self, extension):
super(Myfile, self).__init__()
You may need to create the FileUtil class using the super() function as well:
class FileUtil(object):
def __init__(self):
super(FileUtil, self).__init__()
...
Here is my code
class Game_Events(Setup, Game_Setup):
def __init__(self):
super(Game_Events, self).__init__()
super(Game_Events, self).game_setup(self.map_filename)
But when importing the classes I get:
TypeError: Error when calling the metaclass bases
Cannot create a consistent method resolution
order (MRO) for bases Game_Setup, Setup
Here is the init of Setup:
class Setup(object):
def __init__(self):
self.HERO_MOVE_SPEED = 20 # pixels per second
self.MAP_FILENAME = 'resources/tmx/Fesnoria Town.tmx'
self.MUSIC_FILENAME = "resources/music/Forest_Song.mp3"
Here is the init of Game_Setup:
class Game_Setup(Setup):
def __init__(self):
super(Game_Setup, self).__init__()
I need to import the Setup class first because this contains self.map_filename which I need for the other class below it.
Does anyone know how to fix this?
Game_Setup is a subclass of Setup, but Game_Events is inheriting from both of them, which is not possible. I guess you should only inherit from Game_Setup to make it work.