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

时间:2014-06-01 15:50:56

标签: python pyqt pyside super

短版(tl; dr)

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

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

详细版本

我是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的书(Lutz学习Python)花了20多页关于super的主题,而明确告诫不要使用它。他建议新的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

2 个答案:

答案 0 :(得分: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:我从未见过任何依赖合作多重继承的真实代码。 (单一继承很容易为我制作足够的意大利面条; - ))

另外,一些好的阅读:

[

答案 1 :(得分: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可以说 违反了“明确胜于隐性”的格言,但“简单胜过复杂”和“实用性胜过纯洁”是最重要的因素(这里的实践方面是“可维护性计数”)