子类化时 super() 的使用(误用)

2 投票
2 回答
1364 浏览
提问于 2025-04-18 07:01

在尝试如何让 tkinter 的 FrameLabelFrame 正确地继承父类时,我发现很多回答都建议使用 super().__init__,而不是 BaseClass.__init__() 来进行子类化。

所以我试了一下,想看看这有什么特别之处,但似乎根本不管用。在 Python 2.7 中,它对参数的类型提出了警告。在 3.4 中,它说 master 有多个定义。把 super 注释掉后,代码就能正常工作。我到底哪里出错了呢?

# 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()

我尝试的第一件事就是在调用 super().__init__() 时去掉 self,但是在 Python 2.7 中,不管有没有 self,我都收到了同样的错误信息。

去掉 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

保留 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  

错误信息在去掉 self 后依然保持不变,这说明问题不在这里。而且用 BaseClass 调用时能正常工作,这让我对其他参数可能出错的地方感到困惑。

2 个回答

1

在这种情况下使用 super 时,你不需要明确地传递 self。只需这样写 super(App, self).__init__(master=parent, text='inner')(如果是Python 3,可以写成 super().__init__(master=parent, text='inner'))。

2

如果我没记错的话,

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

应该是这样的 -

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

因为你不应该把 self 作为参数传给父类的 __init__ 方法。

实际上,当使用实例方法时,你不需要显式地传递 self 给任何方法,调用时解释器会自动提供 self

顺便说一下,

    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

这些调用都是多余的。你只需要用其中一个。我更倾向于 -

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

或者

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

但如果你更喜欢用第一个 -

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

确保你去掉 self,改成 -

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

撰写回答