短版(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
答案 0 :(得分:8)
首先,这两者有何不同?如果你有简单的继承(也许不算“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.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
。 可以说 违反了“明确胜于隐性”的格言,但“简单胜过复杂”和“实用性胜过纯洁”是最重要的因素(这里的实践方面是“可维护性计数”)