短版(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
嗯,很好。但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:我从未见过任何依赖合作多重继承的真实代码。 (单遗传很容易为我制作足够的意大利面;-))
还有一些好的阅读:
[
以传统方式实例化父类没有任何问题,有些事情可以说是有利于它。也就是说,使用super
简化了子类的创建,以及未来对一个PySide代码的修改,人们似乎已经将后者作为最重要的因素。这不是Pyside特有的,而是更普遍的Python中的面向对象编程(正如Kos的优秀答案所指出的那样)。
简化代码修改的可能性是因为在PySide中,有必要根据其他QtGui
对象(例如,QtQui.QMainWindow
和QtGui.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
。它可以说违反了“明确胜过隐含”的格言,但“简单胜于复杂”和“实用性胜过纯”是最重要的因素(这里的实践方面是“可维护性计数”)。