Skip to main content
 首页 » 编程设计

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

2025年05月04日19oomusou

我想问一个关于使用 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 class)的构造函数。我看不出任何不起作用的理由。 然而,当我运行它时,出现以下错误:

super(CCanvas,self).__init__(master=master,*args,**kwargs) 
TypeError: must be type, not classobj 

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

请您参考如下方法:

这里的问题是 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 时代有一些方法流传开来……但是你不想那样做。)