Neil_UK
Neil_UK

Reputation: 1083

Use (misuse) of super() when subclassing

While wrestling with how to subclass a tkinter Frame and LabelFrame so they sat on the correct parent, I found a lot of answers suggested that super().__init__ was better than BaseClass.__init()__ when subclassing.

So I tried it, to see what the fuss was about, and it doesn't seem to work at all. In python 2.7, it complains about the types of the arguments. In 3.4, it says there are multiple definitions for master. With super commented out as below, it works as expected. What am I doing wrong?

# import Tkinter as tki   # py 2.7
import tkinter as tki   # py 3.4

class App(tki.LabelFrame):
    def __init__(self, parent):
        tki.LabelFrame.__init__(self, master=parent, text='inner')
        # super().__init__(self, master=parent, text='inner')          #py 3.4
        # super(App, self).__init__(self, master=parent, text='inner') #py 2.7
        # super(App, self).__init__(master=parent, text='inner') #py 2.7

        self.quit = tki.Button(self, text='quit', command=exit)
        self.quit.grid()      

if __name__ == '__main__':    
    root = tki.Tk()
    root.title('nesting testing')

    outer = tki.LabelFrame(root, text='outer level')
    outer.pack()

    app = App(outer)
    app.pack()

    root.mainloop()

Dropping self in the call to super().__init__() was one of the first things I tried, but in py2.7 I still got the same error message, whether it was in there or not.

Without self:

Traceback (most recent call last):  
    File "C:\Python\TESTS\test_super.py", line 21, in <module>  
        app = App(outer)  
    File "C:\Python\TESTS\test_super.py", line 9, in __init__  
        super(App, self).__init__(master=parent, text='inner') #py 2.7  
TypeError: must be type, not classobj

With self:

Traceback (most recent call last):  
  File "C:\Python\TESTS\test_super.py", line 21, in <module>  
    app = App(outer)  
  File "C:\Python\TESTS\test_super.py", line 8, in __init__  
    super(App, self).__init__(self, master=parent, text='inner') #py 2.7  
TypeError: must be type, not classobj  

The fact that the error message stays the same as I drop self suggests that it's not the problem, but the fact it works OK with the BaseClass call is confusing me as to what could be wrong with the other arguments.

Upvotes: 2

Views: 1369

Answers (2)

brainless coder
brainless coder

Reputation: 6430

If I remember correct then

super().__init__(self, master=parent, text='inner')          #py 3.4
super(App, self).__init__(self, master=parent, text='inner') #py 2.7

should have been -

super().__init__(master=parent, text='inner')          #py 3.4
super(App, self).__init__(master=parent, text='inner') #py 2.7

Because you should not pass self as paramter to __init__ of super.

In fact when using instance methods, you should not pass self explicitly to any method, self is automatically provided when the call is made by the interpreter

BTW,

    tki.LabelFrame.__init__(self, master=parent, text='inner')
    super().__init__(self, master=parent, text='inner')          #py 3.4
    super(App, self).__init__(self, master=parent, text='inner') #py 2.7
    super(App, self).__init__(master=parent, text='inner') #py 2.7

All these calls are redundant. You should use only one of them. I would prefer -

    super().__init__(master=parent, text='inner')          #py 3.4

or

    super(App, self).__init__(master=parent, text='inner') #py 2.7

but if you prefer to use the first one -

    tki.LabelFrame.__init__(self, master=parent, text='inner')

make sure you remove the self and make it -

    tki.LabelFrame.__init__(master=parent, text='inner')

Upvotes: 2

BrenBarn
BrenBarn

Reputation: 251353

When using super in this way, you don't pass self explicitly. Just do super(App, self).__init__(master=parent, text='inner') (or super().__init__(master=parent, text='inner') for Python 3).

Upvotes: 1

Related Questions