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
继承了 GUIClass
和 SomeOtherClass
,而 SomeOtherClass
又继承了 Frame
。
如果您现在在GUIclass
和SomeOtherClass
中都使用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 类:继承与实例化的主要内容,如果未能解决你的问题,请参考以下文章