子类化时 super() 的使用(误用)
在尝试如何让 tkinter 的 Frame
和 LabelFrame
正确地继承父类时,我发现很多回答都建议使用 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')