Burkely91
Burkely91

Reputation: 902

Python classes: Inheritance vs Instantiation

I'm creating a GUIclass that uses Frame() as its base class.

In my GUIclass’s init method I want to create a Frame widget

Right now I have:

class GUIclass(Frame):
    def __init__(self, parent):
        frame = Frame(self, parent)   

But I've seen this elsewhere for the third line:

Frame.__init__(self, parent)   

I'm new to programming, python and definitely inheritance and I wanted to know if I understand the difference between the two correctly. I did a lot of researching and reading, I promise, but I couldn't quite find anything that made it completely clear:

In the first situation I don't call the init method as I created a Frame object (frame) and when an object is created its init method is called implicitly by python.

In the second scenario, one is calling the init method on the class (which I believe is totally legit?) because a Frame object wasn't created, so therefore wouldn't do it automatically.

Is that right?

I've also seen:

frame = Frame.__init__(self, parent)   

which really threw me off. Is this just someone doing something redundant or is there a reason for this?

Thank you for your help, I want to take it slow for now and make sure I fully understand any and every line of code I write as I go rather than writing and running a whole program I half understand.

Upvotes: 12

Views: 1453

Answers (2)

janeemac
janeemac

Reputation: 43

You'll have to use Frame.__init__(self, parent) as Tkinter doesn't support super calls

Upvotes: 1

Alfe
Alfe

Reputation: 59436

You should call

super(GUIclass, self).__init__(parent)

This is the proper way to call (all) your inherited __init__() method(s). It has in many cases identical results compared to the mentioned

Frame.__init__(self, parent)

which only lacks the abstraction concerning the inheritance relationships and states the class Frame as the one and only class whose __init__() method you might want to call (more about that later).

The also mentioned

frame = Frame(self.parent)

is wrong in this context. It belongs to another pattern of object relationship, namely contents relationship instead of inheritance relationship (which you aim at). It will create a new object of class Frame instead of initializing the Frame parts of yourself; in inheritance relationships you are a Frame, so you have to initialize yourself as one as well as initializing your specialized parts (which is done in the rest of your __init__() method). In contents relationship models you merely have a Frame.

Now, what about that "slight" difference I mentioned above between calling super(GUIclass, self).__init__(parent) and Frame.__init__(self, parent)?

To understand that you need to dig deeper into inheritance relationships and the various possibilities these offer, especially with multiple inheritance.

Consider a diamond-shaped relationship model which looks like this:

          Frame
          /   \
    GUIclass  SomeOtherClass
          \   /
       AnotherClass

In your current scenario you only have the top left two classes, but one never knows what's going to come, and you should always code in a way so that the next user of your code keeps all options.

In this diamond-shaped pattern you have AnotherClass which inherits GUIClass and SomeOtherClass which in turn both inherit Frame.

If you now use the pattern Frame.__init__(self, parent) in both GUIclass and SomeOtherClass, then calling their __init__() methods from the __init__() method of AnotherClass will result in a doubled calling of the Frame's __init__() method. This typically is not intended, and to take care that this does not happen, the super call was invented. It takes care that a decent calling order calls each of the __init__() methods only and exactly once.

Upvotes: 8

Related Questions