继承自Tkinter.Canvas - 调用super会导致错误

时间:2013-01-17 23:17:05

标签: python inheritance canvas tkinter super

我想问一个关于使用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

任何人都可以向我解释这种行为并告诉我如何解决这个问题吗?

1 个答案:

答案 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天的早期有一些食谱漂浮在后面......但是你没有我想这样做。)