为什么在PySide/PyQt中使用super这么多?

2024-05-14 18:57:00 发布

您现在位置:Python中文网/ 问答频道 /正文

短版本(tl;dr)

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

澄清:正如我在详细版本中更清楚地指出的那样,这不是另一个询问何时使用super(这在以前已经做过)的通用线程。相反,考虑到使用super而不是<class>.__init__的PySide教程的数量,我试图找出在PySide应用程序中使用super是否是标准的?如果是这样,是不是因为调用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)

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

当您拥有继承钻石时,super似乎最有帮助,它倾向于以合理的方式解决多重继承的实例。PySide中是否经常使用super,因为有大量这样的钻石案例,我将面对更为现实的复杂例子?[编辑:否:请参阅下面的答案。]

为什么我还要问?为什么不直接用super来做呢?

我这样问是因为我用来学习Python的书(Lutz的《学习Python》)花了20多页来讨论super这个主题,而且明确警告不要使用它。他建议新的Python用户在使用之前先使用更传统、更明确的方法(例如,参见第832页和第1041-1064页的学习Python,第5版)。他基本上把它描绘成一种非语言的,神秘的,很少实际需要的,新的风格,在刚开始的时候你应该非常小心地对待,并且认为它被有经验的用户过度使用。

此外,查看两个主要的基于PySide/PyQt的项目(Spyder和pyqtgraph)的源代码,它们都不使用super。一个(Spyder)显式地告诉贡献者为了兼容性的原因避免使用它(http://code.google.com/p/spyderlib/wiki/NoteForContributors)。

注意,我链接到了下面一篇密切相关的文章,但是这里的答案更一般地讨论了何时需要使用super(当您有多个继承时)。我的问题是,从长远来看,PySide脚本是否证明或者甚至要求使用super是合理的,或者是否更像python,出于兼容性的原因,更适合显式地命名父类?还是口味问题?

如果它是不受欢迎的(正如我的初学者书所建议的),为什么它在针对初学者的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


Tags: self版本comhttp标准initexample教程
2条回答

用传统的方式实例化父类没有什么错,有些事情应该说是有利于它的。也就是说,使用super简化了子类的创建,以及将来对PySide代码的修改,人们似乎已经将后者作为压倒一切的因素。这并不是Pyside特有的,而是Python中面向对象的编程(正如Kos的优秀回答所指出的)。

简化代码修改的潜力在于,在PySide中,必须根据其他QtGui对象(例如QtQui.QMainWindowQtGui.QWidget)定义子类。此外,人们倾向于充分利用父类,这样似乎更容易使用super,这样就不必每次更改父类时都更新init方法。

因此,使用super来帮助解决多重继承的情况并不是问题,大多数人都认为这种情况最适合。相反,这是一个在in it中减少工作的问题,以防将来父类发生更改。

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

作者1:

I think it is a matter of taste. Earlier tutorials (PyQt and PySide) used .init and later I switched to super(). I personally prefer super().

作者2:

The reason people use super instead of .init(...) is to avoid making changes if you change what the parent class is, e.g. if you switch from QVBoxLayout to QHBoxLayout, you only have to change it in the class definition line, rather than in the init method as well.

好了,给你。这些好处并不是PySide特有的,而是编写子类/继承。

我不确定Lutz会说什么(也许使用super违反了“显式优于隐式”的格言),他似乎很犹豫是否支持使用super

四年后更新 回想起来,这场辩论已经结束了,这个问题几乎很奇怪(这是我第一次问这个问题)。虽然过去有关于使用super的争论,但这些争论已经结束了。尤其是在Python 3中,{}的便利性已经得到了证明,并且使代码更易于维护。因为在Qt/Pyside/PyQt框架中,从更抽象的Qt类继承的使用非常普遍,这是一个不小的特性。当然,当你有疯狂的继承格时,你需要小心,但是坦白地说,自从我问这个问题以来,我从未遇到过这个问题,而且我目前在所有代码中都使用super。可以说,它违反了“显式优于隐式”的格言,但“简单优于复杂”和“实用胜过纯粹”是这里最重要的因素(这里的实用方面是“可维护性计数”)。

嗯,不错。但在我看来,它与Qt/PySide几乎没有关系。

首先,这两个有什么不同?如果你有简单的继承(也许不算“mixin”),那么行为上就没有区别。一个表面上的区别仍然存在-你不需要再命名你的基类-但是你必须命名同一个类。

当您具有多重继承时,差异就开始了。然后由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:我从未见过任何真正的代码依赖于协作多重继承。(单继承很容易为我做足够的意大利面;-))

此外,一些好的阅读:

[

相关问题 更多 >

    热门问题