我想问一个关于使用Canvas作为容器的聪明问题,但编写我的示例代码我偶然发现了一些奇怪的东西。这是迄今为止的代码:
import Tkinter as tk
class CCanvas(tk.Canvas):
def __init__(self,master,*args,**kwargs):
super(CCanvas,self).__init__(master=master,*args,**kwargs)
if __name__ == '__main__':
root= tk.Tk()
cc = CCanvas(root)
cc.pack()
root.mainloop()
现在这段代码不应该做太多。 CCanvas类继承自Canvas,没有实现任何东西,只调用超类的构造函数。我认为没有任何理由不这样做。 然而,当我运行它时,我收到以下错误:
super(CCanvas,self).__init__(master=master,*args,**kwargs)
TypeError: must be type, not classobj
任何人都可以向我解释这种行为并告诉我如何解决这个问题吗?
答案 0 :(得分:6)
这里的问题是TkInter类(在2.x中)是旧式类。 Data Model文档中详细描述了这些差异,但您无需了解详细信息。您需要知道的是you can't use super
(以及如何通过显式调用__init__
来解决这个问题)。而且,正如Steven Rumbalski所指出的那样,super() fails with error: TypeError “argument 1 must be type, not classobj”解释了当您尝试super
的基类在旧式类上时,为什么会收到此错误消息。
文档中没有提到这一点,除非你去寻找它,否则它并不是很明显,但如果你知道如何区分这两者,那就不那么难了。
正如thread on python-list所指出的,这通常不是问题,因为如果你需要新式的类行为,你可以随时做class CCanvas(tk.Canvas, object):
。
但是有一些事情没有处理,其中之一就是能够super
到基类。相反,你必须以老式的方式做事,并通过名称明确地引用基类(这也意味着你必须明确地传递self
):
def __init__(self,master,*args,**kwargs):
TkInter.Canvas.__init__(self, master=master, *args, **kwargs)
(当然另一种解决方案是迁移到Python 3,没有旧式类......)
(为了完整起见,有可能用旧式课程假冒90%的super
,并且在2.x天的早期有一些食谱漂浮在后面......但是你没有我想这样做。)