Python 类:继承与实例化

Posted

技术标签:

【中文标题】Python 类:继承与实例化【英文标题】:Python classes: Inheritance vs Instantiation 【发布时间】:2015-07-27 23:41:15 【问题描述】:

我正在创建一个使用 Frame() 作为其基类的 GUI 类。

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

现在我有:

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

但我在其他地方看到了第三行:

Frame.__init__(self, parent)   

我是编程、python 和继承的新手,我想知道我是否正确理解了两者之间的区别。我保证,我做了很多研究和阅读,但我找不到任何可以完全清楚的东西:

在第一种情况下,我没有调用 init 方法,因为我创建了一个 Frame 对象(框架),并且当一个对象被创建时,它的 init 方法被 python 隐式调用。

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

对吗?

我也看过:

frame = Frame.__init__(self, parent)   

这真的让我失望。这只是某人做了多余的事情还是有原因?

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

【问题讨论】:

你应该使用第二个:Frame.__init__(self, parent) 第一个是不正确的,因为它在基于帧的对象的初始化程序中创建了一个不必要的帧。 第二个和第三个是对框架中父初始化器的超级调用,这样子类的初始化器将扩展基础,而不是覆盖基础。但是没有必要分配 super 调用的结果,使第三个不正确。 最好的解决方案是在 python2 中使用super().__init__(*arguments)(假设是python3),这将是super(GUIclass, self).__init__(*arguments)(假设是新型类)。此外,PEP8 要求调用类GUIClass 很遗憾,Tkinter 不支持超级调用, 【参考方案1】:

你应该打电话

super(GUIclass, self).__init__(parent)

这是调用(全部)继承的__init__() 方法的正确方法。与上述相比,它在许多情况下具有相同的结果

Frame.__init__(self, parent)

它仅缺少关于继承关系的抽象,并将类 Frame 声明为您可能想要调用其 __init__() 方法的唯一类(稍后会详细介绍)。

也提到了

frame = Frame(self.parent)

在这种情况下是错误的。它属于另一种对象关系模式,即 contents 关系而不是 inheritance 关系(您的目标)。它将创建一个 Frame 类的新对象,而不是初始化你自己的 Frame 部分;在继承关系中,您Frame,因此您必须将yourself 初始化为一个以及初始化您的专用部分(这在__init__() 方法的其余部分中完成)。在 contents 关系模型中,您只需 拥有 Frame

现在,我上面提到的调用super(GUIclass, self).__init__(parent)Frame.__init__(self, parent) 之间的“细微”差异呢?

要了解您需要深入挖掘继承关系及其提供的各种可能性,尤其是多重继承。

考虑如下所示的菱形关系模型:

          Frame
          /   \
    GUIclass  SomeOtherClass
          \   /
       AnotherClass

在您当前的场景中,您只有左上角的两个类,但永远不知道会发生什么,并且您应该始终以某种方式编码,以便您的代码的下一个用户保留所有选项。

在这个菱形图案中,AnotherClass 继承了 GUIClassSomeOtherClass,而 SomeOtherClass 又继承了 Frame

如果您现在在GUIclassSomeOtherClass 中都使用Frame.__init__(self, parent) 模式,那么从AnotherClass__init__() 方法调用它们的__init__() 方法将导致对Frame 的双重调用的__init__() 方法。这通常不是故意的,为了避免这种情况发生,发明了super 调用。请注意,体面的调用顺序仅调用每个 __init__() 方法一次。

【讨论】:

super 参数按另一个顺序排列。 谢谢,已解决。 (我从来不记得那些正确的,所以如果你恶作剧我,我只是改变了那个;-) 啊,现在一切都说得通了,我想我看到了不同之处。那么我是否正确地说第一个确实在技术上初始化了一个框架,但它创建了一个单独的框架对象,而不是说这个对象具有这些框架属性,然后是一些 - 然后是我的子类中的其他任何东西 init ? 我也看到了在其他人出现时编写不会崩溃的代码的用途,现在我一个人在做,但我希望有一天能成为一名程序员,所以这很棒我还没有考虑过的建议。最好现在就开始练习!如果可以的话,我会加十个 是的,第一个创建一个单独的对象并且不初始化self的框架方面。 Tkinter 是否支持super:任何继承object 的类都支持super 机制。我不确定哪个 Tkinter 类是您的 Frame,但您可以查看 Frame.__bases__ 以查看 <type 'object'> 是否被它继承。如果不是,不要使用super 机制,而是坚持Frame.__init__(self, parent) 模式。【参考方案2】:

你必须使用Frame.__init__(self, parent),因为 Tkinter 不支持超级调用

【讨论】:

以上是关于Python 类:继承与实例化的主要内容,如果未能解决你的问题,请参考以下文章

Python中类的内置方法与继承关系实例

类继承接口使用接口实例化 与 使用类实例化

python类和实例化

python的类定义与实例化

Python中没有抽象方法的抽象数据类:禁止实例化

学习 Python 之 面向对象