The API still looks messy and unpythonic though, sadly. Look at the basic hello world example. Why do I need to pass QApplication an empty array? Why am I calling a method ending with _ to launch the program? And the fact the label magically attaches to the app through some side effect is also confusing.
Does anyone know if there's any good shim/wrapper around PyQt that has a better API?
Maybe it's not pythonic but I can assure you, after having passed 6 years working with it that it's extremely efficient and very well integrated with python. It just works, and a complaint about aesthetics won't change that :-)
I second that. Maybe the interface isn't very Pythonic, but it's very Qt-ic, if that's a word. The behavior of PyQt hews closely to the behavior described in Qt's excellent C++ documentation. Furthermore, PyQt lets you do things that you may take for granted, like connecting signals to Python functions and subclassing Qt Widgets. And not only can you subclass a Qt Widget, you can override its methods. Also, you can send a Python str to any method that accepts a QString. I could go on and on about how the boring stuff stays pleasantly boring.
Having used much worse Python bindings for other C++ libraries, the degree to which PyQt just works without blowing up in your face is itself pretty astonishing. Add to that the maturity and depth of the Qt Widget library, and the result is a real pleasure to use.
My first foray with Qt was also my first (serious) foray with Python, so it was easy for me to ignore pythonicity and just write something that approximately resembles Qt's existing style.
Knowing some of my coworkers, though (who use Python daily), I can understand why it'd be jarring.
The now-official bindings (Qt for Python as mentioned in the article) has a waaay more Pythonic API. I actually liked it. The advantage of PyQt5 is that you can look up the Qt documentation.
Qt for Python and PyQt5 have almost exactly the same API, to the point where it took me 30 min to migrate my 15kLoC project [1] from the latter to the former, mostly by changing a few imports. Maybe you meant something else?
Had a very similar experience a few years back migrating from PySide to PyQt when PySide wasn't able to keep up with Qt. Fixing the imports took minutes and we were off to the races.
Since Python 3 you can use exec() instead of exec_() (in Python 2 exec was a keyword).
> And the fact the label magically attaches to the app through some side effect is also confusing.
Are you referring to the first "label.show()" example?
Typically that pattern is rare (~once per app for the main window). Regarding attachment to the app; QApplication is a process-wide singleton. All objects belong to the same app.
Not exactly what you're asking for, but QtPy - https://github.com/spyder-ide/qtpy - is a nice abstraction layer that sits between your program and either PyQt5 or PySide2.
The confusion will go away if you learn how things work under the hood(you should know what an event loop is, learn about Qt widgets parenting, signals and slots, layouts),also in practice you use the GUI tools to create and modify GUIs though you need to learn how to use them properly and not create absolute positioned layouts.
Does anyone know if there's any good shim/wrapper around PyQt that has a better API?