Short version (tl;dr)
I am learning PySide, and most online tutorials use super
to initialize UI elements. Is this important (i.e., more scalable), or is it a matter of taste?
Clarification: as I make more clear in the detailed version, this is not another generic thread asking when to use super
(this has been done before). Rather, given the number of PySide tutorials that use super
instead of <class>.__init__
, I am trying to figure out if using super
is standard in PySide applications? If so, is it because the circumstances where super
is called for (involving resolving inheritances) come up a lot specifically in the use of PySide/PyQt? Or is it a matter of taste.
Detailed version
I am new to Python, and presently learning PySide using Zets tutorial (http://zetcode.com/gui/pysidetutorial/firstprograms/). The second example in the tutorial includes:
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_())
This works fine, but I have never used super
. Hence, I rewrote the above code, successfully replacing super
with more standard explicit invocation of the parent class:
QtGui.QWidget.__init__(self)
But as I search the web for PySide tutorials (e.g., http://qt-project.org/wiki/PySide-Newbie-Tutorials), they all include calls to super
. My question is: should I use super
for PySide scripting?
It seems that super
seems most helpful when you have inheritance diamonds, that it tends to resolve instances of multiple inheritance in a reasonable way. Is super
used a lot with PySide because there is a preponderance of cases of such diamonds that I will confront with more realistic complicated examples? [Edit: No: see my answer below.]
Why am I even asking? Why not just use super
and be done with it?
I am asking because the book I am using to learn Python (Learning Python, by Lutz) spends over 20 pages on the topic of super
, and explicitly cautions against using it. He suggests that new Python users go with the more traditional, explicit route before messing with it (e.g., see page 832, and pages 1041-1064 of Learning Python, 5th Edition). He basically paints it as a nonPythonic, arcane, rarely actually needed, new style that you should treat with great caution when just starting out, and thinks it is overused by experienced users.
Further, looking at the source code of two major PySide/PyQt based projects (Spyder and pyqtgraph), neither uses super
. One (Spyder) explicitly tells contributors to avoid using it for compatibility reasons (http://code.google.com/p/spyderlib/wiki/NoteForContributors).
Note I link to a closely related post below, but the answer there discusses more generally when you would want to use super
(when you have multiple inheritance). My question is whether PySide scripting justifies, or even requires, the use of super
in the long term, or whether it is more Pythonic, and better for compatibility reasons, to explicitly name parent classes? Or is it a matter of taste?
If it is frowned upon (as my beginner book suggests) why is it so ubiquitous in PySide tutorials aimed at beginners? If it makes any difference, it seems the people writing these tutorials are seasoned Java programmers, or catering to such programmers. I am not.
Related topics
http://www.riverbankcomputing.com/pipermail/pyqt/2008-January/018320.html
Different ways of using __init__ for PyQt4
Understanding Python super() with __init__() methods
Hm, nice one. But IMO it's only barely related to Qt/ PySide.
First, how are these two different? If you have simple inheritance (perhaps not counting "mixins"), then there's no difference in behaviour. A cosmetic difference remains- you don't need to name your base class again - but you do have to name the same class.
The differences start when you have multiple inheritance. Then a chain of super()
calls for this hierarchy:
A
/ \
X Y
\ /
Z
can easily proceed like this through super()
calls:
A
\
X --- Y
\
Z
without the need of X and Y knowing each other. This relates to the concept of method resolution order that allows a style of programming called "cooperative multiple inheritance" in the Python docs.
If there's a method Foo
and implementations in X and Y of that method build upon A's implementation, then Z is easily able to rely on both X and Y without them knowing even about each other. This, however, has an important precondition: Foo
has the same (or at least [compatible]) signature in every class, as specified by A
's interface where it's initially defined.
The __init__
method is special: technically it works in exactly the same way with super
, but! but (more often than not) for subclasses it has a totally different signature. If the subclass' __init__
looks different, then super
won't give you anything over explicit base call because you aren't able to use cooperative multitasking anyway.
Note: Python is very atypical in this respect: in most OO languages constructors belong to the class, rather than the instances; in other words most languages rely on their equivalents of __new__
and don't have __init__
at all.
Note 2: I have never seen any real code that would rely of cooperative multiple inheritance. (Single inheritance easily makes enough spaghetti for me ;-))
Also, some good reading:
- Method resolution order - what's it all about
- Python's Super is nifty, but you can't use it
[
I have what I consider a provisional answer after studying this, working with PySide the last week, and emailing the authors of two tutorials on PySide (one of whom uses super, the other doesn't, in the tutorial).
Namely, the use of super
is largely a matter of taste, in that there is nothing wrong with instantiating parent classes in the traditional way, and some things to be said in favor of it. However, at least on the surface, using super
does seem to simplify future modifications of one's PySide code, and people seem to have latched onto this as the overriding factor.
The potential for simplification of code modification comes because within PySide it is common to define subclasses based on QtGui objects (e.g., QtQui.QMainWindow
and QtGui.QWidget
). Further, people tend to futz around with their parent classes enough so that it seems easier to just use super
, so that you you don't have to update your __init__ function every time you change parents.
So it isn't a matter of using super
to help resolve cases of multiple inheritance, the case where most people agree it is probably best suited. Rather, it is a matter of doing less work within __init__ in case your parent class changes in the future.
Here are the responses from each author, both of whom wrote what I consider to be good PySide tutorials:
Author 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().
Author 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.
So there you have it. Not sure if this is really specific to PySide, or writing subclasses more generally.
I'm not sure what Lutz, who seems very hesitant to endorse the use of super
, would say (perhaps using super
violates the 'Explicit is better than implicit' maxim, for starters). I will post more on this as I try to better understand his concerns with the function.