Python类:继承与实例化

12

我正在创建一个GUI类,其基类为Frame()。

在我的GUI类的init方法中,我想创建一个Frame小部件。

现在我的代码是:

class GUIclass(Frame):
    def __init__(self, parent):
        frame = Frame(self, parent)   

但是我在其他地方看到过第三行的这个表述:

Frame.__init__(self, parent)   

我刚刚开始学习编程,对Python和继承一无所知。我想了解两者之间的区别是否正确理解。我做了许多研究和阅读,但是没有找到任何完全清晰的说明:

在第一种情况下,我没有调用init方法,因为我创建了一个Frame对象(frame),并且当对象创建时,Python会自动隐式调用其init方法。

在第二种情况下,我们需要调用类(class)的init方法(我认为这完全合法?),因为没有创建Frame对象,因此它不会自动执行。

我的理解是正确的吗?

我也看到过:

frame = Frame.__init__(self, parent)   

这真的让我感到困惑。这只是某人做了一些冗余的事情,还是有什么原因呢?

谢谢您的帮助,我现在想慢慢来,确保我完全理解我写下的每一行代码,而不是写下并运行一个我只有一半理解的整个程序。


1
你应该使用第二个:Frame.__init__(self, parent) - Malik Brahimi
3
第一个是错误的,因为它在基于帧的对象的初始化器中创建了一个不必要的框架。 - Malik Brahimi
1
第二个和第三个是在框架中对父级初始化程序的super调用,以便子类的初始化程序将扩展基础知识,而不是覆盖基础知识。但是没有必要分配超级调用的结果,这使得第三个不正确。 - Malik Brahimi
4
жңҖдҪіи§ЈеҶіж–№жЎҲжҳҜеңЁPython3дёӯдҪҝз”Ёsuper().__init__(*arguments)пјҢеңЁPython2дёӯдҪҝз”Ёsuper(GUIclass, self).__init__(*arguments)пјҲеҒҮи®ҫдёәж–°ејҸзұ»пјүгҖӮжӯӨеӨ–пјҢPEP8规е®ҡе°Ҷзұ»е‘ҪеҗҚдёәGUIClassгҖӮ - Sebastian Riese
很遗憾,在Tkinter中不支持超级调用。 - Burkely91
2个回答

8

你应该调用

super(GUIclass, self).__init__(parent)

这是调用(所有)继承的__init__()方法的正确方式。在许多情况下,它与上述方法具有相同的结果。
Frame.__init__(self, parent)

这个仅缺少有关继承关系的抽象,并将类Frame表示为唯一一个可能想要调用__init__()方法的类(稍后详细介绍)。

上述也提到了

frame = Frame(self.parent)

在这个上下文中,Frame.__init__(self, parent)是错误的。它属于另一种对象关系模式,即内容关系而不是你所追求的继承关系。它将创建一个类为Frame的新对象,而不是初始化自己的Frame部分;在继承关系中,你一个Frame,因此你必须像初始化你的专用部分一样初始化yourself作为一个Frame(这是在你的__init__()方法的其余部分完成的)。在内容关系模型中,你仅仅拥有一个Frame
现在,我提到的super(GUIclass, self).__init__(parent)Frame.__init__(self, parent)之间的“轻微”差异是什么呢?
要理解这一点,你需要深入研究继承关系以及它们提供的各种可能性,特别是多重继承。
考虑一个菱形关系模型,它看起来像这样:
          Frame
          /   \
    GUIclass  SomeOtherClass
          \   /
       AnotherClass

在您目前的情况下,您仅拥有左上角的两个类,但永远不知道未来会发生什么,您应该始终以一种方式编写代码,以便代码的下一个用户保留所有选项。
在这个菱形模式中,您有一个继承 GUIClassSomeOtherClassAnotherClass,而后者又都继承了 Frame
如果现在在 GUIclassSomeOtherClass 中都使用模式 Frame.__init__(self, parent),那么从 AnotherClass__init__() 方法中调用它们的 __init__() 方法将导致重复调用 Frame__init__() 方法。 这通常是不想要的,为了确保这不会发生,发明了 super 调用。它确保一个合理的调用顺序只调用每个 __init__() 方法一次且仅一次。

super参数的顺序与其他相反。 - user2357112
谢谢,已经修正了。 (我总是记不住那些,所以如果你恶作剧了我,我只是让它变得更糟了;-)) - Alfe
啊,现在一切都清楚了,我想我看到了区别。那么,我说第一个技术上确实初始化了一个框架,但它创建了一个单独的框架对象,而不是说这个对象具有这些框架属性,然后再加上一些其他的东西 - 这些其他的东西就是我的子类__init__中的任何其他内容,这样说对吗? - Burkely91
我也认为编写代码时考虑到其他人的使用是很有必要的。虽然现在我还是一个独立开发者,但我希望有一天能成为一名程序员,所以这是一个非常好的建议,我之前没有想过。最好现在就开始实践!如果可以的话,我会给这个建议点赞十次的。 - Burkely91
还有一件事,目前我正在使用Tkinter进行这个项目,我可以说Tkinter不支持super调用吗?在Tkinter中是否有另一种方法,或者我只需坚持使用__init__? - Burkely91
1
是的,第一个创建了一个单独的对象,并且没有初始化self的框架方面。Tkinter是否支持super:任何继承了object的类都支持super机制。我不确定Tkinter中哪个类是您的Frame,但您可以查看Frame.__bases__来查看它是否继承了<type 'object'>。如果没有,请不要使用super机制,而要坚持使用Frame.__init__(self, parent)模式。 - Alfe

1

由于Tkinter不支持super调用,您将需要使用Frame.__init__(self, parent)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接