Different ways of using __init__ for PyQt4 - python

So... I'm working on trying to move from basic Python to some GUI programming, using PyQt4. I'm looking at a couple different books and tutorials, and they each seem to have a slightly different way of kicking off the class definition.
One tutorial starts off the classes like so:
class Example(QtGui.QDialog):
def __init__(self):
super(Example, self).__init__()
Another book does it like this:
class Example(QtGui.QDialog):
def __init__(self, parent=None):
super(Example, self).__init__(parent)
And yet another does it this way:
class Example(QtGui.QDialog):
def__init__(self, parent=None):
QtGui.QWidget.__init__(self, parent)
I'm still trying to wrap my mind around classes and OOP and super() and all... am I correct in thinking that the last line of the third example accomplishes more or less the same thing as the calls using super() in the previous ones, by explicitly calling the base class directly? For relatively simple examples such as these, i.e. single inheritance, is there any real benefit or reason to use one way vs. the other? Finally... the second example passes parent as an argument to super() while the first does not... any guesses/explanations as to why/when/where that would be appropriate?

The first one simply doesn't support passing a parent argument to its base class. If you know that you'll never need the parent arg, that's fine, but this is less flexible.
Since this example only has single inheritance, super(Example, self).__init__(parent) is exactly the same as QtGui.QDialog.__init__(self, parent); the former uses super to get a "version" of self that calles QtGui.QDialog's methods instead of Example's, so that self is automatically included, while the latter directly calls the function QtGui.QDialog.__init__ and explicitly passes the self and parent arguments. In single inheritance there's no difference AFAIK other than the amount of typing and the fact that you have to change the class name if you change inheritance. In multiple inheritance, super resolves methods semi-intelligently.
The third example actually uses QWidget instead of QDialog, which is a little weird; presumably that works because QDialog is a subclass of QWidget and doesn't do anything meaningful in its __init__, but I don't know for sure.

Related

PyQt5 QGraphicsItem odd inheritance behaviour

This is a problem I've found the solution to, but not the answer to. The following is the relevant part of my code:
class MyClass(QGraphicsPolygonItem, MyAbstractGraphicsShapeItem, MyGraphicsItem)
def __init__(self):
super(MyClass, self).__init__()
The first class is the type of graphics object I'm trying to create. For me, the first one I did was a polygon. The second class is one which needed to inherit QAbstractGraphicsShapeItem to change the objects color through. The third class works with any QGraphicsItem. To make everything modular and reusable, this was my setup.
The issue I faced was as such:
If the first class was after the second class, MyClass would no longer recognize it had a polygon I could set.
If the third class was before the second class, MyClass would stop painting itself, showing up in no way on screen.
As you can see, the sequence shown in my code is the only one that works. One of the sequences (third, first, second) even crashes the program. Here is what I think happens:
The graphic item classes inherit in this order, from superclass <--- subclass.
QGraphicsItem <--- QAbstractGraphicsShapeItem <--- QGraphicsPolygonItem
When the initialization priority is the same as the inheritance direction from subclasses to superclasses, the inheritance works.
The Point
This is what I think the initialization order looks like in these situations:
MyAbstractgraphicsShapeItem, QGraphicsPolygonItem, MyGraphicsItem, QAbstractGraphicsShapeItem, QGraphicsItem
QGraphicsPolygonItem, MyGraphicsItem, MyAbstractgraphicsShapeItem, QAbstractGraphicsShapeItem, QGraphicsItem
QGraphicsPolygonItem, MyAbstractgraphicsShapeItem, MyGraphicsItem, QAbstractGraphicsShapeItem, QGraphicsItem
Where the third is the working one.
I cannot see the difference between them. I know how it should work but not why. The initialization order shouldn't matter, as the super call should order them like this, where there are no conflicts between functionality. I know that QAbstractGraphicsShapeItem doesn't have boundingRect or paint functions, but I believe they should be overwritten by QGraphicsPolygonItem class functions. I would like an answer, because this was a really baffling issue to solve.
Edit:
I'll add the other two classes, just the relevant parts:
class MyGraphicsItem(QGraphicsItem):
def __init__(self):
super(MyQGraphicsItem, self).__init__()
class MyAbstractGraphicsShapeItem(QAbstractGraphicsShapeItem):
def __init__(self):
super(MyAbstractGraphicsShapeItem, self).__init__()
For additional detail, MyGraphicsItem allows me to place graphics items in relation to the parent as I wish, while MyAbstractGraphicsShapeItem allows me to create button like behavior (since QAbstractButton only works with QWidgets).

How to do multiple inheritance from different classes in python using super()?

Lets say we have different kind of people, pianist,programmer and multitalented person.
so, How do i inherit like this? currently this code gives error Multitalented has no attribute canplaypiano.
class Pianist:
def __init__(self):
self.canplaypiano=True
class Programer:
def __init__(self):
self.canprogram=True
class Multitalented(Pianist,Programer):
def __init__(self):
self.canswim=True
super(Pianist,self).__init__()
super(Programer,self).__init__()
Raju=Multitalented()
print(Raju.canswim)
print(Raju.canprogram)
print(Raju.canplaypiano)
Also Please mention some well written article about python inheritance/super() i couldnt find a perfect article with clear explaination. thankyou.
All classes involved in cooperative multiple inheritance need to use super, even if the static base class is just object.
class Pianist:
def __init__(self):
super().__init__()
self.canplaypiano=True
class Programer:
def __init__(self):
super().__init__()
self.canprogram=True
class Multitalented(Pianist,Programer):
def __init__(self):
super().__init__()
self.canswim=True
Raju=Multitalented()
print(Raju.canswim)
print(Raju.canprogram)
print(Raju.canplaypiano)
The order in which the initializers run is determined by the method resolution order for Multitalented, which you can affect by changing the order in which Multitalented lists its base classes.
The first, if not best, article to read is Raymond Hettinger's Python's super() Considered Super!, which also includes advice on how to adapt classes the don't themselves use super for use in a cooperative multiple-inheritance hierarchy, as well as advice on how to override a function that uses super (in short, you can't change the signature).
Dont call super with explicit parent classes. In modern python versions (don't know exactly since which version) you call super without parameters. That is, in you case you should have had only one line, not two:
super().__init__()
In somewhat older versions you need to provide the class explicitly, however you should provide the class of "current" object, and the super function takes care of finding out the parent classes. In you case it should be:
super(Multitalented, self).__init__()

Keeping classes loosely coupled and sharing data

I've been working in python on a project where I have a GUI which I split up a bunch of the work between classes. I don't know a lot of the best practices for passing data around between classes, and I've frequently run into the issue, where I have to implement something, or change something for work, and I've resorted to making a lot of the classes objects of another class in order to give it the data I need.
Any ideas or suggests would be greatly appreciated on how to keep my classes independent for later modification and still pass the relevant data around without affecting interfaces too much?
As an example
class Window():
def __init__(self, parent=None):
self.parent = parent
def doStuff(self):
#do work here
class ParseMyWork(Window):
def __init__(self, parent=None):
self.parent=parent
I often find myself doing stuff like the above giving objects to class Window
or simply inheriting everything from them as in ParseMyWork
There must be better and cleaner ways of passing data around without making my classes utterly dependent on eachother, where one little change creates a cascade effect that forces me to make changes in a bunch of other classes.
Any answers to the question don't necessarily have to be in python, but it will be helpful if they are
If I'm understanding your question correctly, I would say that inheritance is not necessary in your case. Why not give ParseMyWork a function for dealing with a specific Window task?
class Window():
def __init__(self, parent=None):
self.parent = parent
def doStuff(self):
#do work here
class ParseMyWork():
def __init__(self, parent=None):
self.parent=parent`
def doWindowActivity(self, window):
window.doStuff
Then you can use the function like this
work_parser = ParseMyWork()
window = Window()
work_parser.doWindowActivity(window);
That way you can use your work_parse instance with any window instance.
Apologies in advance for my Python, it's been a while so if you see any rookie mistakes, do point them out.
Keep it simple.py:
def doStuff(window):
#do work here
return window
def parseStuff(stuff):
pass
really.py:
from simple import doStuff, parseStuff
def really_simple(window):
okay = doStuff(window)
return parseStuff(okay)
don't complicate the class:
from really import really_simple
really_simple(window)
imo: classes are overly complicated objects, and in a lot of cases more confusing than they need to be, plus they hold references and modify stuff, and can be difficult to decouple once they have been tied to other classes. if there isn't a clear reason why a class needs to be used, then it probably doesn't need to be used.
Classes are super powerful, so it's good you're getting started with em.
Discalimer: Haven't worked in python for a while now, so things might not be exact. The general idea still applies though.
Getting into your question now:
I would say the best way to achieve what you want is to create an instance of the first object where you will extract information from.
Now when creating a class, it's vital that you have attributes within them that you will want to be stored within it that you would like to retrieve once the class is instantiated.
For example, using your Window class example above, let's say that you have an attribute called resolution. It would look something like this:
class Window():
def __init__(self, parent = None):
self.parent = None
self.resolution = '40x80'
Now the resolution information associated with your Window class is forever part of any Window class instance. Now, the next step would be to create a get method for resolution. This should be done as follow:
class Window():
def __init__(self, parent = None):
self.parent = None
self.resolution = '40x80'
def getResoultion():
return self.resolution
Now, the reason we created this get method is because we can now set a variable to the information that is returned with it.
So let's say that you have everything associated with your Window class in its own file (let's say the file name is called Window.py). In a separate file (let's call it main.py), you can do the following:
import Window
windowInstance = Window()
windowResolution = windowInstance.getResolution()
If you print out the variable windowResolution, you should get that 40x80 printed out.
Now, as a side note, I do believe it is possible to get the information associated with an attribute with an instance of a class by simply doing something like
windowResolution = windowInstance.resolution
but that is bad practice in general. The reason, in a nutshell, is because you are now exposing attribute names of your class which you do not want to do because it makes it easy for a person outside of your code to learn the name where that information is held and change it. This can then lead to a myriad of other problems when it comes to making an overall program work. That is why it is best practice to use getters and setters. I already showed what getters are. Simply a get method for attributes. Setters, as you can probably assume, allow for one to set the information of an attribute to something else. Now you might say "Gabe, if we can create setter methods, what's the point of it if they just change it". My answer to that is to not give a setter method to all attributes. For attributes you don't mind for a person to change, give it a setter method, but for attributes you do not want any outside users to touch, simply don't create a setter method for it. Same goes with getter methods too. Users don't need to see all of the information of all attributes that makes your program work. Here's a better explanation: https://en.wikipedia.org/wiki/Mutator_method
Now, back to your example. Now let's say you have your ParseMyWork class in its own file like we did with your Window class, and let's say that ParseMyWork needs the resolution info from Window class. You can do the following :
import Window
import ParseMyWork
windowInstance = Window()
windowResolution = windowInstance.getResolution()
parseInstance = ParseMyWork(windowResolution)
This will only pass the window resolution information associated with your Window class. Hope this helps.

Is __init__ a class method?

I was looking into Python's super method and multiple inheritance. I read along something like when we use super to call a base method which has implementation in all base classes, only one class' method will be called even with variety of arguments. For example,
class Base1(object):
def __init__(self, a):
print "In Base 1"
class Base2(object):
def __init__(self):
print "In Base 2"
class Child(Base1, Base2):
def __init__(self):
super(Child, self).__init__('Intended for base 1')
super(Child, self).__init__()# Intended for base 2
This produces TyepError for the first super method. super would call whichever method implementation it first recognizes and gives TypeError instead of checking for other classes down the road. However, this will be much more clear and work fine when we do the following:
class Child(Base1, Base2):
def __init__(self):
Base1.__init__(self, 'Intended for base 1')
Base2.__init__(self) # Intended for base 2
This leads to two questions:
Is __init__ method a static method or a class method?
Why use super, which implicitly choose the method on it's own rather than explicit call to the method like the latter example? It looks lot more cleaner than using super to me. So what is the advantage of using super over the second way(other than writing the base class name with the method call)
super() in the face of multiple inheritance, especially on methods that are present on object can get a bit tricky. The general rule is that if you use super, then every class in the hierarchy should use super. A good way to handle this for __init__ is to make every method take **kwargs, and always use keyword arguments everywhere. By the time the call to object.__init__ occurs, all arguments should have been popped out!
class Base1(object):
def __init__(self, a, **kwargs):
print "In Base 1", a
super(Base1, self).__init__()
class Base2(object):
def __init__(self, **kwargs):
print "In Base 2"
super(Base2, self).__init__()
class Child(Base1, Base2):
def __init__(self, **kwargs):
super(Child, self).__init__(a="Something for Base1")
See the linked article for way more explanation of how this works and how to make it work for you!
Edit: At the risk of answering two questions, "Why use super at all?"
We have super() for many of the same reasons we have classes and inheritance, as a tool for modularizing and abstracting our code. When operating on an instance of a class, you don't need to know all of the gritty details of how that class was implemented, you only need to know about its methods and attributes, and how you're meant to use that public interface for the class. In particular, you can be confident that changes in the implementation of a class can't cause you problems as a user of its instances.
The same argument holds when deriving new types from base classes. You don't want or need to worry about how those base classes were implemented. Here's a concrete example of how not using super might go wrong. suppose you've got:
class Foo(object):
def frob(self):
print "frobbign as a foo"
class Bar(object):
def frob(self):
print "frobbign as a bar"
and you make a subclass:
class FooBar(Foo, Bar):
def frob(self):
Foo.frob(self)
Bar.frob(self)
Everything's fine, but then you realize that when you get down to it,
Foo really is a kind of Bar, so you change it
class Foo(Bar):
def frob(self):
print "frobbign as a foo"
Bar.frob(self)
Which is all fine, except that in your derived class, FooBar.frob() calls Bar.frob() twice.
This is the exact problem super() solves, it protects you from calling superclass implementations more than once (when used as directed...)
As for your first question, __init__ is neither a staticmethod nor a classmethod; it is an ordinary instance method. (That is, it receives the instance as its first argument.)
As for your second question, if you want to explicitly call multiple base class implementations, then doing it explicitly as you did is indeed the only way. However, you seem to be misunderstanding how super works. When you call super, it does not "know" if you have already called it. Both of your calls to super(Child, self).__init__ call the Base1 implementation, because that is the "nearest parent" (the most immediate superclass of Child).
You would use super if you want to call just this immediate superclass implementation. You would do this if that superclass was also set up to call its superclass, and so on. The way to use super is to have each class call only the next implementation "up" in the class hierarchy, so that the sequence of super calls overall calls everything that needs to be called, in the right order. This type of setup is often called "cooperative inheritance", and you can find various articles about it online, including here and here.

What's the difference between these ways of calling the superclass's constructor?

What if anything is the important difference between the following uses of calling the superclass initiation function?
class Child_1(Parent):
def __init__(self):
super(Child, self).__init__()
class Child_2(Parent):
def __init__(self):
super(Parent, self).__init__()
class Child_3(Parent):
def __init__(self):
Parent.__init__(self)
The first form (though you'd fix the typo and make it Child_1 in the call to super) would be what you'd generally want. This will look up the correct method in the inheritence hierarchy.
For the second form, you're looking for parents classes of Parent that implement this method, and you'd have to have a very special use case (if you want to skip a parent, don't derive from them) in order to want to do that.
The third in many cases would wind up doing the same as the first, though without seeing the code for Parent, it's hard to be sure. The advantage of the first method over the third is that you can change the base class of the child and the right method will still be called.
Also, the first form allows for cooperative multiple inheritence. See this post or this writeup to understand the cases where this would be useful or necessary.

Categories