Is it necessary to call super().__init__() explicitly in python? - python

I came from Java where we can avoid calling super class zero-argument constructor. The call to it is generated implicitly by the compiler.
I read this post about super() and now in question about is it really necessary to do something like this explicitly:
class A(object):
def __init__(self):
print("world")
class B(A):
def __init__(self):
print("hello")
super().__init__() #Do we get some Undefined Behavior if we do not call it explicitly?

If you override the __init__ method of the superclass, then the __init__ method of the subclass needs to explicitly call it if that is the intended behavior, yes.
Your mental model of __init__ is incorrect; it is not the constructor method, it is a hook which the constructor method calls to let you customize object initialization easily. (The actual constructor is called __new__ but you don't need to know this, and will probably never need to interact with it directly, let alone change it.)

Related

running __init__ inside its own definition

I'm currently learning tkinter from sentdex's tutorial and to me it seems that I'm writing to run __init__ in its own definition, what does a line like that mean? Is it tKinter's __init__ function?
class seaOfBTCapp(tk.Tk):
def __init__(self,*args,**kwargs)
tk.Tk.__init__(self,*args,**kwargs)
It's invoking another class's constructor on itself.
This is a fun quirk of python's object-oriented design. "Instance methods" are really just class methods that take the current instance as an implicit parameter. You can, in fact, call them as class methods and provide the object explicitly:
ex = [1, 2, 3, 4, 5]
# the following are equivalent:
ex.pop(0) # call the method on the instance, passing it implicitly
list.pop(ex, 0) # call the method on the class `list`, passing the instance explicitly
The same behavior is being invoked here. You're taking the __init__ method of the tk.TK class, and passing self in as the "instance". This is an uncommon, but valid, way of accessing methods in the superclass that have been overridden in your subclass (for example, the constructor).
As in #Barmar's answer, a better solution is using super(), which produces something resembling an instance of the superclass, which you then call __init__ on to get the superclass's implementation of __init__() passing self implicitly, as you would expect.
What that line does is call your parent class's __init__ method. That's what would have happened if you didn't define your own method, so if you're not doing anything else in your __init__, you should probably just skip it and let the inherited method run normally.
It's also probably better to call super().__init__(*args, **kwargs), rather than naming the parent class explicitly (and needing to pass self by hand). This is particularly the case if you might ever use this class in a situation involving multiple inheritance, where explicitly naming the next class to be called can get the MRO wrong. If you're just starting in programming, don't worry too much about this, multiple inheritance is a pretty advanced topic (though it's easier to get right in Python than in many other languages).
I think this is equivalent to the more modern:
class seaOfBTCapp(tk.Tk):
def __init__(self,*args,**kwargs)
super().__init__(*args,**kwargs)

Call a method in initialization without overriding base class's __init__

I hope I make it clear in the title. I'm trying to inherit from list, and I want some of my own methods to be called when an instance of my class is created. However, I can't override list.__init__ since that would make me unable to use list's original methods. How can I accomplish this?
Simply call super.__init__ before / after you call your own methods:
class CustomList(list):
def __init__(self, *args):
super(CustomList, self).__init__(*args)
# call your own methods here

Mutliple constructors in python calling the same routine

I am writing a class with multiple constructors using #classmethod. Now I would like both the __init__ constructor as well as the classmethod constructor call some routine of the class to set initial values before doing other stuff.
From __init__ this is usually done with self:
def __init__(self, name="", revision=None):
self._init_attributes()
def _init_attributes(self):
self.test = "hello"
From a classmethod constructor, I would call another classmethod instead, because the instance (i.e. self) is not created until I leave the classmethod with return cls(...). Now, I can call my _init_attributes() method as
#classmethod
def from_file(cls, filename=None)
cls._init_attributes()
# do other stuff like reading from file
return cls()
and this actually works (in the sense that I don't get an error and I can actually see the test attribute after executing c = Class.from_file(). However, if I understand things correctly, then this will set the attributes on the class level, not on the instance level. Hence, if I initialize an attribute with a mutable object (e.g. a list), then all instances of this class would use the same list, rather than their own instance list. Is this correct? If so, is there a way to initialize "instance" attributes in classmethods, or do I have to write the code in such a way that all the attribute initialisation is done in init?
Hmmm. Actually, while writing this: I may even have greater trouble than I thought because init will be called upon return from the classmethod, won't it? So what would be a proper way to deal with this situation?
Note: Article [1] discusses a somewhat similar problem.
Yes, you'r understanding things correctly: cls._init_attributes() will set class attributes, not instance attributes.
Meanwhile, it's up to your alternate constructor to construct and return an instance. In between constructing it and returning it, that's when you can call _init_attributes(). In other words:
#classmethod
def from_file(cls, filename=None)
obj = cls()
obj._init_attributes()
# do other stuff like reading from file
return obj
However, you're right that the only obvious way to construct and return an instance is to just call cls(), which will call __init__.
But this is easy to get around: just have the alternate constructors pass some extra argument to __init__ meaning "skip the usual initialization, I'm going to do it later". For example:
def __init__(self, name="", revision=None, _skip_default_init=False):
# blah blah
#classmethod
def from_file(cls, filename=""):
# blah blah setup
obj = cls(_skip_default_init=True)
# extra initialization work
return obj
If you want to make this less visible, you can always take **kwargs and check it inside the method body… but remember, this is Python; you can't prevent people from doing stupid things, all you can do is make it obvious that they're stupid. And the _skip_default_init should be more than enough to handle that.
If you really want to, you can override __new__ as well. Constructing an object doesn't call __init__ unless __new__ returns an instance of cls or some subclass thereof. So, you can give __new__ a flag that tells it to skip over __init__ by munging obj.__class__, then restore the __class__ yourself. This is really hacky, but could conceivably be useful.
A much cleaner solution—but for some reason even less common in Python—is to borrow the "class cluster" idea from Smalltalk/ObjC: Create a private subclass that has a different __init__ that doesn't super (or intentionally skips over its immediate base and supers from there), and then have your alternate constructor in the base class just return an instance of that subclass.
Alternatively, if the only reason you don't want to call __init__ is so you can do the exact same thing __init__ would have done… why? DRY stands for "don't repeat yourself", not "bend over backward to find ways to force yourself to repeat yourself", right?

Python Inheritance and __init__

I'm learning Python and I've found something about how Python constructs a sub class which confuses me.
I have a class that inherits from the list class as follows.
class foo(list):
def __init__(self, a_bar):
list.__init__([])
self.bar = a_bar
I know that list.__init__([]) needs to be there but I'm confused about it. It seems to me that this line will just create a new list object and then assign it to nothing, so I would suspect that it would just get garbage collected. How does Python know that this list is part of my object? I suspect that there is something happening behind the scenes and I'd like to know what it is.
The multiple-inheritance-safe way of doing it is:
class foo(list):
def __init__(self, a_bar):
super(foo, self).__init__()
...
which, perhaps, makes it clearer that you're calling the baseclass ctor.
You usually do this when subclassing and overriding the __init__() function:
list.__init__(self)
If you're using Python 3, you can make use of super():
super().__init__()
The actual object is not created with __init__ but with __new__. __init__ is not for creating the object itself but for initializing it --- that is, adding attributes, etc. By the time __init__ is called, __new__ has already been called, so in your example the list was already created before your code even runs. __init__ shouldn't return anything because it's supposed to initialize the object "in-place" (by mutating it), so it works by side-effects. (See a previous question and the documentation.)
You're partly right:
list.__init__([])
"creates a new list object." But this code is wrong. The correct code _should_be:
list.__init__(self)
The reason you need it to be there is because you're inheriting from a list that has it's own __init__() method where it (presumably) does important to initialize itself. When you define your own __init__() method, you're effectively overriding the inherited method of the same name. In order to make sure that the parent class's __init__() code is executed as well, you need to call that parent class's __init__().
There are several ways of doing this:
#explicitly calling the __init__() of a specific class
#"list"--in this case
list.__init__(self, *args, **kwargs)
#a little more flexible. If you change the parent class, this doesn't need to change
super(foo, self).__init__(*args, **kwargs)
For more on super() see this question, for guidance on the pitfalls of super, see this article.

Should __init__() call the parent class's __init__()?

I'm used that in Objective-C I've got this construct:
- (void)init {
if (self = [super init]) {
// init class
}
return self;
}
Should Python also call the parent class's implementation for __init__?
class NewClass(SomeOtherClass):
def __init__(self):
SomeOtherClass.__init__(self)
# init class
Is this also true/false for __new__() and __del__()?
Edit: There's a very similar question: Inheritance and Overriding __init__ in Python
If you need something from super's __init__ to be done in addition to what is being done in the current class's __init__, you must call it yourself, since that will not happen automatically. But if you don't need anything from super's __init__, no need to call it. Example:
>>> class C(object):
def __init__(self):
self.b = 1
>>> class D(C):
def __init__(self):
super().__init__() # in Python 2 use super(D, self).__init__()
self.a = 1
>>> class E(C):
def __init__(self):
self.a = 1
>>> d = D()
>>> d.a
1
>>> d.b # This works because of the call to super's init
1
>>> e = E()
>>> e.a
1
>>> e.b # This is going to fail since nothing in E initializes b...
Traceback (most recent call last):
File "<pyshell#70>", line 1, in <module>
e.b # This is going to fail since nothing in E initializes b...
AttributeError: 'E' object has no attribute 'b'
__del__ is the same way, (but be wary of relying on __del__ for finalization - consider doing it via the with statement instead).
I rarely use __new__. I do all the initialization in __init__.
In Anon's answer:
"If you need something from super's __init__ to be done in addition to what is being done in the current class's __init__ , you must call it yourself, since that will not happen automatically"
It's incredible: he is wording exactly the contrary of the principle of inheritance.
It is not that "something from super's __init__ (...) will not happen automatically" , it is that it WOULD happen automatically, but it doesn't happen because the base-class' __init__ is overriden by the definition of the derived-clas __init__
So then, WHY defining a derived_class' __init__ , since it overrides what is aimed at when someone resorts to inheritance ??
It's because one needs to define something that is NOT done in the base-class' __init__ , and the only possibility to obtain that is to put its execution in a derived-class' __init__ function.
In other words, one needs something in base-class' __init__ in addition to what would be automatically done in the base-classe' __init__ if this latter wasn't overriden.
NOT the contrary.
Then, the problem is that the desired instructions present in the base-class' __init__ are no more activated at the moment of instantiation. In order to offset this inactivation, something special is required: calling explicitly the base-class' __init__ , in order to KEEP , NOT TO ADD, the initialization performed by the base-class' __init__ .
That's exactly what is said in the official doc:
An overriding method in a derived class may in fact want to extend
rather than simply replace the base class method of the same name.
There is a simple way to call the base class method directly: just
call BaseClassName.methodname(self, arguments).
http://docs.python.org/tutorial/classes.html#inheritance
That's all the story:
when the aim is to KEEP the initialization performed by the base-class, that is pure inheritance, nothing special is needed, one must just avoid to define an __init__ function in the derived class
when the aim is to REPLACE the initialization performed by the base-class, __init__ must be defined in the derived-class
when the aim is to ADD processes to the initialization performed by the base-class, a derived-class' __init__ must be defined , comprising an explicit call to the base-class __init__
What I feel astonishing in the post of Anon is not only that he expresses the contrary of the inheritance theory, but that there have been 5 guys passing by that upvoted without turning a hair, and moreover there have been nobody to react in 2 years in a thread whose interesting subject must be read relatively often.
In Python, calling the super-class' __init__ is optional. If you call it, it is then also optional whether to use the super identifier, or whether to explicitly name the super class:
object.__init__(self)
In case of object, calling the super method is not strictly necessary, since the super method is empty. Same for __del__.
On the other hand, for __new__, you should indeed call the super method, and use its return as the newly-created object - unless you explicitly want to return something different.
Edit: (after the code change)
There is no way for us to tell you whether you need or not to call your parent's __init__ (or any other function). Inheritance obviously would work without such call. It all depends on the logic of your code: for example, if all your __init__ is done in parent class, you can just skip child-class __init__ altogether.
consider the following example:
>>> class A:
def __init__(self, val):
self.a = val
>>> class B(A):
pass
>>> class C(A):
def __init__(self, val):
A.__init__(self, val)
self.a += val
>>> A(4).a
4
>>> B(5).a
5
>>> C(6).a
12
There's no hard and fast rule. The documentation for a class should indicate whether subclasses should call the superclass method. Sometimes you want to completely replace superclass behaviour, and at other times augment it - i.e. call your own code before and/or after a superclass call.
Update: The same basic logic applies to any method call. Constructors sometimes need special consideration (as they often set up state which determines behaviour) and destructors because they parallel constructors (e.g. in the allocation of resources, e.g. database connections). But the same might apply, say, to the render() method of a widget.
Further update: What's the OPP? Do you mean OOP? No - a subclass often needs to know something about the design of the superclass. Not the internal implementation details - but the basic contract that the superclass has with its clients (using classes). This does not violate OOP principles in any way. That's why protected is a valid concept in OOP in general (though not, of course, in Python).
IMO, you should call it. If your superclass is object, you should not, but in other cases I think it is exceptional not to call it. As already answered by others, it is very convenient if your class doesn't even have to override __init__ itself, for example when it has no (additional) internal state to initialize.
Yes, you should always call base class __init__ explicitly as a good coding practice. Forgetting to do this can cause subtle issues or run time errors. This is true even if __init__ doesn't take any parameters. This is unlike other languages where compiler would implicitly call base class constructor for you. Python doesn't do that!
The main reason for always calling base class _init__ is that base class may typically create member variable and initialize them to defaults. So if you don't call base class init, none of that code would be executed and you would end up with base class that has no member variables.
Example:
class Base:
def __init__(self):
print('base init')
class Derived1(Base):
def __init__(self):
print('derived1 init')
class Derived2(Base):
def __init__(self):
super(Derived2, self).__init__()
print('derived2 init')
print('Creating Derived1...')
d1 = Derived1()
print('Creating Derived2...')
d2 = Derived2()
This prints..
Creating Derived1...
derived1 init
Creating Derived2...
base init
derived2 init
Run this code.

Categories