为什么在PySide / PyQt中超级使用了这么多?

问题描述 投票:13回答:2

短版(tl; dr)

我正在学习PySide,大多数在线教程都使用super来初始化UI元素。这是重要的(即更具可扩展性),还是品味问题?

澄清:当我在详细版本中更清楚时,这不是另一个通用线程,询问何时使用super(这已经在之前完成)。相反,考虑到使用super而不是<class>.__init__的PySide教程的数量,我试图弄清楚使用super是否是PySide应用程序的标准?如果是这样,是因为需要super的情况(涉及解决继承问题)在使用PySide / PyQt时出现了很多问题?或者这是品味问题。

详细版本

我是Python的新手,目前正在使用Zets教程(http://zetcode.com/gui/pysidetutorial/firstprograms/)学习PySide。本教程的第二个示例包括:

from PySide import QtGui

class Example(QtGui.QWidget):
    def __init__(self):      
        super(Example, self).__init__()
        self.initUI()
    def initUI(self):
        self.setGeometry(300,300,250,150)
        self.setWindowTitle("PySide 101: Window the First!")
        self.show()

app=QtGui.QApplication(sys.argv)
ex=Example()
sys.exit(app.exec_())    

这很好,但我从来没有使用过super。因此,我重写了上面的代码,成功地用更标准的父类的显式调用替换super

QtGui.QWidget.__init__(self)

但是当我在网上搜索PySide教程(例如,http://qt-project.org/wiki/PySide-Newbie-Tutorials)时,它们都包含对super的调用。我的问题是:我应该使用super进行PySide脚本编写吗?

当你拥有继承钻石时,似乎super似乎最有用,它倾向于以合理的方式解决多重继承的实例。 super是否在PySide中使用了很多,因为这些钻石的案例占优势,我将面对更现实的复杂例子? [编辑:否:请参阅下面的答案。]

我为什么要问?为什么不使用super并完成它?

我问,因为我用来学习Python的书(学习Python,由Lutz撰写)在super的主题上花费了20多页,并明确告诫不要使用它。他建议新的Python用户在使用它之前采用更传统,更明确的路线(例如,参见第832页,学习Python的第1041-1064页,第5版)。他基本上将它描绘成一种非剧性的,神秘的,很少需要的新风格,刚开始时你应该非常谨慎地对待它,并认为它被有经验的用户过度使用。

此外,查看两个主要的PySide / PyQt项目(Spyder和pyqtgraph)的源代码,都没有使用super。 One(Spyder)明确告诉贡献者出于兼容性原因而避免使用它(http://code.google.com/p/spyderlib/wiki/NoteForContributors)。

注意我链接到下面一个密切相关的帖子,但是当你想要使用super(当你有多个继承)时,那里的答案会更一般地讨论。我的问题是PySide脚本是否证明甚至要求长期使用super,或者它是否更具Pythonic,并且出于兼容性原因更好地明确命名父类?还是味道问题?

如果它不受欢迎(正如我的初学者所说),为什么它在针对初学者的PySide教程中如此普遍?如果它有任何区别,那么编写这些教程的人似乎是经验丰富的Java程序员,或者迎合这些程序员。我不是。

相关话题

http://www.riverbankcomputing.com/pipermail/pyqt/2008-January/018320.html

Different ways of using __init__ for PyQt4

Understanding Python super() with __init__() methods

python pyqt pyside super
2个回答
8
投票

嗯,很好。但IMO与Qt / PySide几乎没有关系。

首先,这两者有何不同?如果你有简单的继承(也许不算“mixins”),那么行为就没有区别了。化妆品差异仍然存在 - 您不需要再次命名基类 - 但您必须命名同一个类。

当您有多个继承时,差异就会开始。然后super()链调用这个层次结构:

          A
        /   \
       X     Y
        \   /
          Z

可以通过super()调用轻松地进行:

          A
            \
       X --- Y
        \   
          Z

不需要X和Y相互了解。这与method resolution order的概念有关,它允许在the Python docs中称为“合作多重继承”的编程风格。

如果有一个方法Foo,并且该方法的X和Y中的实现建立在A的实现上,那么Z很容易依赖于X和Y,而他们甚至不知道彼此。然而,这有一个重要的前提条件:Foo在每个类中都有相同(或至少[兼容])的签名,正如A最初定义的接口所指定的那样。

__init__方法很特别:从技术上讲,它与super完全相同,但是!但是(通常情况下),对于子类,它具有完全不同的签名。如果子类'__init__看起来不同,那么super将不会给你任何超过显式基本调用的东西,因为你无论如何都无法使用协作式多任务处理。

注意:Python在这方面非常不典型:在大多数OO语言中,构造函数属于类,而不是实例;换句话说,大多数语言依赖于他们的__new__等价物而根本没有__init__

注2:我从未见过任何依赖合作多重继承的真实代码。 (单遗传很容易为我制作足够的意大利面;-))

还有一些好的阅读:

[


6
投票

以传统方式实例化父类没有任何问题,有些事情可以说是有利于它。也就是说,使用super简化了子类的创建,以及未来对一个PySide代码的修改,人们似乎已经将后者作为最重要的因素。这不是Pyside特有的,而是更普遍的Python中的面向对象编程(正如Kos的优秀答案所指出的那样)。

简化代码修改的可能性是因为在PySide中,有必要根据其他QtGui对象(例如,QtQui.QMainWindowQtGui.QWidget)来定义子类。此外,人们倾向于使用他们的父类足够多,以便使用super似乎更容易,这样您每次更换父母时都不必更新__init__方法。

所以这不是使用super来帮助解决多重继承的问题,大多数人都认为它可能是最适合的情况。相反,如果您的父类将来发生变化,则需要在__init__中减少工作量。

以下是每位作者的回复,他们都写了我认为好的PySide教程:

作者1:

我认为这是一个品味问题。早期教程(PyQt和PySide)使用.init,后来我切换到super()。我个人更喜欢super()。

作者2:

人们使用super而不是.init(...)的原因是为了避免在更改父类的内容时进行更改,例如如果从QVBoxLayout切换到QHBoxLayout,则只需在类定义行中更改它,而不是在init方法中更改它。

所以你有它。这些好处并非特定于PySide,而是更普遍地编写子类/继承。

我不确定Lutz,他似乎非常犹豫地赞同使用super,会说(也许使用super违反了'明确胜过隐含'格言)。

四年后更新 回想起来,这场辩论已经结束了,这个问题几乎是古怪的(这是我在SO的第一个问题)。虽然曾经有关于使用super的辩论,但这些争论已经结束了。特别是在Python 3中,super的便利性已经证明了自己,只是让你的代码更容易维护。因为在Qt / Pyside / PyQt框架中,使用来自更抽象的Qt类的继承是无处不在的,这不是一个小特征。当然,当你有疯狂的继承格式时,你需要小心,但坦率地说,因为我问过这个问题,我实际上从来没有遇到过这个问题,而且我目前在我的所有代码中使用super。它可以说违反了“明确胜过隐含”的格言,但“简单胜于复杂”和“实用性胜过纯”是最重要的因素(这里的实践方面是“可维护性计数”)。

© www.soinside.com 2019 - 2024. All rights reserved.