1

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

谁能向我解释这种行为,也许可以告诉我如何解决它?

4

1 回答 1

6

这里的问题是 TkInter 类(在 2.x 中)是旧式类。数据模型文档中详细描述了这些差异,但您无需了解详细信息;所有你需要知道的是你不能使用super(以及如何通过显式调用来解决这个问题__init__)。而且,正如 Steven Rumbalski 指出的那样,super() 失败并出现错误:TypeError “argument 1 must be type, not classobj”</a> 解释了为什么当您尝试super使用旧的基类时会收到此错误消息风格的类。

这在文档中没有提到,除非你去寻找它,否则它并不是很明显,但如果你知道如何区分这两者,这并不难。

正如在 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 的早期有一些食谱在流传……但你不想那样做。)

于 2013-01-17T23:33:35.667 回答