I have a problem about analyzing these lines of code, if you want to view the whole code I can post it.
Can you guys please explain whats going on here?
I'm planning to create a database program with tkinter and sqlite, I have a windows PC.
I didnt write the code I just want to study it.
class meh(Tkinter.Frame):
def __init__(self, parent):
Tkinter.Frame.__init__(self, parent)
self.parent=parent
self.initialize_user_interface()
Whats going on here?
def __init__(self, parent):
Tkinter.Frame.__init__(self, parent)
Python supports object-oriented programming. One of the core concepts in OOP is inheritance, which means that a class can "inherit" methods from another class. For instance
class Animal:
def __init__(self, name): # The __init__ function is called when an object is
self.name = name # instantiated. That's called a "constructor"
print('Created ' + name)
def make_sound(self):
print("...")
def die(self):
print(self.name + ' died.')
class Cat(Animal): # The class in the parenthesis is the superclass.
def make_sound(self): # A cat makes a different sound from any other animal,
print("Meow") # so we give it its own make_sound method. But it dies
# the same as any other animal, so it will inherit
# the die method from the superclass.
Now when we try this code:
>>> fluffy = Animal('Fluffy')
Created Fluffy
>>> fluffy.make_sound()
...
>>> fluffy.die()
Fluffy died.
>>> kitty = Cat("Kitty")
Created Kitty
>>> kitty.make_sound()
Meow
>>> kitty.die()
Kitty died.
So now, let's look at the code you gave:
class meh(Tkinter.Frame):
This line creates a class that inherits from Tkinter.Frame. That means that it should be able to do anything that a Frame can do, which will probably be things like containing UI elements.
def __init__(self, parent):
This is a constructor that gets called when you create a new meh. It takes parent as a parameter. I'd check the documentation, but in UI development, that often means interface element that this one should appear inside. For instance, the parent might be a window or another frame.
Tkinter.Frame.__init__(self, parent)
This is calling the __init__ method of the class Tkinter.Frame. This basically means that instead of defining something to do instead of what Tkinter.Frame does in its constructor, they're defining things to do in addition to Tkinter.Frame.__init__.
Related
According to Python docs super()
is useful for accessing inherited methods that have been overridden in
a class.
I understand that super refers to the parent class and it lets you access parent methods. My question is why do people always use super inside the init method of the child class? I have seen it everywhere. For example:
class Person:
def __init__(self, name):
self.name = name
class Employee(Person):
def __init__(self, **kwargs):
super().__init__(name=kwargs['name']) # Here super is being used
def first_letter(self):
return self.name[0]
e = Employee(name="John")
print(e.first_letter())
I can accomplish the same without super and without even an init method:
class Person:
def __init__(self, name):
self.name = name
class Employee(Person):
def first_letter(self):
return self.name[0]
e = Employee(name="John")
print(e.first_letter())
Are there drawbacks with the latter code? It looks so much cleanr to me. I don't even have to use the boilerplate **kwargs and kwargs['argument'] syntax.
I am using Python 3.8.
Edit: Here's another stackoverflow questions which has code from different people who are using super in the child's init method. I don't understand why. My best guess is there's something new in Python 3.8.
The child might want to do something different or more likely additional to what the super class does - in this case the child must have an __init__.
Calling super’s init means that you don’t have to copy/paste (with all the implications for maintenance) that init in the child’s class, which otherwise would be needed if you wanted some additional code in the child init.
But note there are complications about using super’s init if you use multiple inheritance (e.g. which super gets called) and this needs care. Personally I avoid multiple inheritance and keep inheritance to aminimum anyway - it’s easy to get tempted into creating multiple levels of inheritance/class hierarchy but my experience is that a ‘keep it simple’ approach is usually much better.
The potential drawback to the latter code is that there is no __init__ method within the Employee class. Since there is none, the __init__ method of the parent class is called. However, as soon as an __init__ method is added to the Employee class (maybe there's some Employee-specific attribute that needs to be initialized, like an id_number) then the __init__ method of the parent class is overridden and not called (unless super.__init__() is called) and then an Employee will not have a name attribute.
The correct way to use super here is for both methods to use super. You cannot assume that Person is the last (or at least, next-to-last, before object) class in the MRO.
class Person:
def __init__(self, name, **kwargs):
super().__init__(**kwargs)
self.name = name
class Employee(Person):
# Optional, since Employee.__init__ does nothing
# except pass the exact same arguments "upstream"
def __init__(self, **kwargs):
super().__init__(**kwargs)
def first_letter(self):
return self.name[0]
Consider a class definition like
class Bar:
...
class Foo(Person, Bar):
...
The MRO for Foo looks like [Foo, Person, Bar, object]; the call to super().__init__ inside Person.__init__ would call Bar.__init__, not object.__init__, and Person has no way of knowing if values in **kwargs are meant for Bar, so it must pass them on.
class ClsOne(object):
def __init__(self):
super(ClsOne, self).__init__()
print "Here's One"
class ClsTwo(ClsOne):
def __init__(self):
super(ClsTwo, self).__init__()
print "Here's Two"
class ClsThree(ClsTwo): # Refer to one blackbox object
def __init__(self):
# super(ClsThree, self).__init__()
print "Here's Three"
class ClsThreee(ClsTwo): # Refer to your custom object
def __init__(self):
super(ClsThreee, self).__init__()
print "Here's Threee"
class ClsFour(ClsThree, ClsThreee): # Multiple Inheritance
def __init__(self):
super(ClsFour, self).__init__()
print "Here's Four"
entity = ClsFour()
In this case, you are trying to combine ClsThree (which comes from a single compiled library and is very hard to change) and your own ClsThreee object together. Because ClsThree forgets to call super() in its constructor, their kid cannot execute ClsThreee's constructor when it uses super().
As a result, the output will just like this:
Here's Three
Here's Four
Obviously, I can manually call every bases of ClsFour rather than use super(), but it's a bit complicated when this problem scattered all over my codebase.
By the way, that blackbox stuff is PySide :)
SUPPLEMENT:
Thanks to #WillemVanOnsem and #RaymondHettinger, the previous ClsFour question is solved. But with some further investigations, I found the similar problem in PySide doesn't have same concept.
In ClsFour context, if you try to run:
print super(ClsFour, self).__init__
You'll get:
<bound method ClsFour.__init__ of <__main__.ClsFour object at 0x00000000031EC160>>
But in the following PySide context:
import sys
from PySide import QtGui
class MyObject(object):
def __init__(self):
super(MyObject, self).__init__()
print "Here's MyObject"
class MyWidget(QtGui.QWidget, MyObject):
def __init__(self):
super(MyWidget, self).__init__()
app = QtGui.QApplication(sys.argv)
widget = MyWidget()
print super(MyWidget, widget).__init__
The result is:
<method-wrapper '__init__' of MyWidget object at 0x0000000005191D88>
It doesn't print "Here's MyObject" and the init attribute of super() has a different type as well. Previously, I try to simplify this problem as the ClsFour. But now I think it isn't totally the same.
I guess the problem occurs in shiboken library but I'm not sure.
TIPS:
The problem also appear in PyQt context, but you can make MyObject inherit from QObject to solve. This solution is useless in PySide.
super() is a proxy object that uses the Method Resolution Order (MRO) to determine what method to call when you perform a call on super().
If we inspect the __mro__ of ClassFour, we get:
>>> ClsFour.__mro__
(<class '__main__.ClsFour'>, <class '__main__.ClsThree'>, <class '__main__.ClsThreee'>, <class '__main__.ClsTwo'>, <class '__main__.ClsOne'>, <type 'object'>)
Or made it shorter myself (not the Python output):
>>> ClsFour.__mro__
(ClsFour, ClsThree, ClsThreee, ClsTwo, ClsOne, object)
Now super(T,self) is a proxy object that uses the MRO from (but excluding) T. So that means that super(ClsFour,self) is a proxy object that works with:
(ClsThree, ClsThreee, ClsTwo, ClsOne, object) # super(ClsFour,self)
What will happen if you query an attribute (a method is also an attribute) of a class is that Python will walk through the MRO and inspect whether the element has such attribute. So it will first inspect whether ClsThree has an __init__ attribute, if not it will continue to look for it in ClsThreee and so on. From the moment it finds such attribute it will stop, and return it.
So super(ClsFour,self).__init__ will return the ClsThree.__init__ method. The MRO is also used to find methods, attributes, etc. that are not defined on the class level. So if you use self.x and x is not an attribute of the object nor of the ClsFour object, it will again walk through the MRO in search for x.
If you want to call the __init__ of all the direct parents of ClassFour you can use:
class ClsFour(ClsThree, ClsThreee):
def __init__(self):
# call *all* *direct* parents __init__
for par in ClsFour.__bases__:
par.__init__(self)
Which is probably the most elegant, since if the bases change, it will still work. Note that you have to make sure that __init__ exists for every parent. Since it is however defined at the object level, we can safely assume this. For other attributes however, we can not make that assumption.
EDIT: Mind that as a result super() does not necessary points to the parents, grandparents and/or ancestors of that class. But to parent classes of the object.
The super(ClsThree,self) in the ClsThree class, will - given it is an ClsFour object, work with the same mro (since it takes the mro from the self). So super(ClsThree,self) will inspect the following sequence of classes:
(ClsThreee, ClsTwo, ClsOne, object)
For instance, if we write (out of the scope of any class) super(ClsTwo,entity).__init__(), we get:
>>> super(ClsTwo,entity).__init__()
Here's One
>>> super(ClsThree,entity).__init__()
Here's Two
Here's Threee
>>> super(ClsThreee,entity).__init__()
Here's Two
>>> super(ClsFour,entity).__init__()
Here's Three
Summary
Because ClsThree forgets to call super() in its constructor, their kid cannot execute ClsThreee's constructor when it uses super().
This is covered in the "How to Incorporate a Non-cooperative Class" section of Super Considered Super blog post.
The key is to create an adapter class that plays by the rules to act cooperatively by calling super(). Use that adapter to wrap the original class.
Worked-out code
In the code below, AdaptThree is the new adapter class and ClsFour
now inherits from AdaptThree instead of the original blackbox non-cooperative class.
class ClsOne(object):
def __init__(self):
print "Here's One"
class ClsTwo(ClsOne):
def __init__(self):
print "Here's Two"
class ClsThree(ClsTwo): # Refer to one blackbox object
def __init__(self):
# super(ClsThree, self).__init__()
print "Here's Three"
class AdaptThree(object):
def __init__(self):
_three = ClsThree()
super(AdaptThree, self).__init__()
class ClsThreee(ClsTwo): # Refer to your custom object
def __init__(self):
super(ClsThreee, self).__init__()
print "Here's Threee"
class ClsFour(AdaptThree, ClsThreee): # Multiple Inheritance
def __init__(self):
super(ClsFour, self).__init__()
print "Here's Four"
entity = ClsFour()
This outputs:
Here's Three
Here's Two
Here's Threee
Here's Four
Other details
In OP's example, ClsTwo also looks to be non-cooperative and should wrapped as well.
Presumably these classes with have methods other than initialization. The adapter classes will need to wrap and dispatch those calls as well.
Depending on the application, it may be easier to use composition rather than inheritance.
Regarding the issue specific to PySide/PyQt4: one solution is to ensure that any mixins always preceed the Qt classes in the base-class definition:
import sys
from PySide import QtGui
class MyObject(object):
def __init__(self, parent=None, other=None):
super(MyObject, self).__init__(parent)
print "Here's MyObject: %r" % other
class MyWidget(MyObject, QtGui.QWidget):
def __init__(self, parent=None, other=None):
super(MyWidget, self).__init__(parent, other)
app = QtGui.QApplication(sys.argv)
parent = QtGui.QWidget()
widget = MyWidget(parent, 'FOO')
print super(MyWidget, widget).__init__
# check that the QWidget.__init__ was called correctly
print 'widget.parent() is parent:', widget.parent() is parent
Output:
Here's MyObject: 'FOO'
<bound method MyWidget.__init__ of <__main__.MyWidget object at 0x7f53b92cca28>>
widget.parent() is parent: True
(NB: PyQt5 has improved Support for Cooperative Multi-inheritance, so this issue doesn't arise there).
In Functions class, I would like to access the variable of the Frame class.
Please tell me if there is any way.
class Functions():
def changeText():
...
...
I want to change the 'text' in the Frame class
ex )Frame.text.SetFont('change text')
GUI element
class Frame(wx.Frame):
def __init__(self, parent, id, title):
wx.Frame.__init__(self, parent, id, title, ....)
....
....
self.text = wx.StaticText(panel, .....)
You can do this by sending an instance of the class to the function:
class myClass(object):
def __init__(self, text):
self.text = text
def changeText(input):
input.text = "world"
example = myClass("hello")
changeText(example)
You will have to tell your objects what to work on. Out of thin air your Functions instance will not know (how should it?) what Frame should be. You could make Frame a global, but I do not think that is a good idea (it will break if you want to work with more than one frame instance). So you would write:
class Functors:
...
def set_text(txt_frame, the_text):
"""txt_frame has to be a :class:`my_txt_frm` instance with ``self.text`` being a ``StaticText`` instance."""
txt_frame.text.SetLabel(the_text)
class my_txt_frm(wx.Frame): # do not name the derived class Frame to make more clear it is derived!
def __init__(# ...
...
self.text = wx.StaticText(#...
So now comes the interesting part: how to tie the parts together? You have to have something like that somewhere in your code:
funct = Functors() # the class which know how to do things on our GUI elements
frm = my_txt_frm(#...
Some lines later...
funct.set_text(frm, 'thenewtext')
So for your app which has the bigger picture it is necessary to keep references to the building blocks to be able to tie them together later.
An orderly way to tie things together is called MVC (see a great example in the wxPython wiki). Even if you do not want to model your app after this paradigm, you can learn from it how to reason about separation of concerns.
I am learning PyQt5 and I tried to create a extended widgets.
I am also learning OOP so I lack experience for this project.
My final goal is to have master widgets that can disable/enable some slave widgets.
So far I need check and radio buttons.
So I tried to create an abstract class that contains the extended behavior of the widgets (the management of the state of the slaves widgets):
class QDisablingWidget():
__metaclass__ = ABCMeta
def __init__(self):
self.slaveWidgets = []
self.slaveStateWhenMasterIsEnabled = {}
def addSlaveWidget(self, slaveWidget, isEnabledWhenMasterIsEnabled=True):
[...]
def updateSlaveStatus(self):
[...]
Then I create my extended widget classes:
class QDisablingCheckBox(QtWidgets.QCheckBox, QDisablingWidget):
def __init__(self, text=None, parent=None, isInMutexGroup=False):
super(QtWidgets.QCheckBox, self).__init__()
super(QDisablingWidget, self).__init__()
if text:
self.setText(text)
if parent:
self.setParent(parent)
self.isInMutexGroup = isInMutexGroup
# Click signal handling
self.stateChanged.connect(self.updateSlaveStatus)
class QDisablingRadioButton(QtWidgets.QRadioButton, QDisablingWidget):
def __init__(self, text=None, parent=None, isInMutexGroup=False):
super(QtWidgets.QRadioButton, self).__init__()
super(QDisablingWidget, self).__init__()
if text:
self.setText(text)
if parent:
self.setParent(parent)
self.isInMutexGroup = isInMutexGroup
# Click signal handling
self.toggled.connect(self.updateSlaveStatus)
You can already see the problem:
I need to connect my self.updateSlaveStatus to the correct signals (stateChanged and toggled) so I added it in the constructor of the derived classes.
Recently I also added the isInMutexGroup argument for some implementation reasons and I realize that I am duplicating the code in both derived classes...
It is the first time I try to use OOP "for real" (first attempt of multiple inheritance and abstract class), so even if I know I am breaking the beauty of the OOP concept, I don't know what to do to get a nice class hierarchy...
So basically, I am looking for a solution on this example. But I am also looking for guidelines, general advice, tutorials, etc. Actually anything that could help me!
Thank you for your help.
Even if I got a downvote for that question, I think some beginners could be interested by the solution I found:
I have my extension abstract class like that:
class QDisablingWidget(QtCore.QObject):
__metaclass__ = ABCMeta
def __init__(self, isInMutexGroup=False, **kwds):
[...]
Then I can derive class like that:
class QDisablingCheckBox(QtWidgets.QCheckBox, QDisablingWidget):
def __init__(self, **kwds):
super().__init__(**kwds)
# On click signal handling
self.stateChanged.connect(self.updateSlaveStatus)
and
class QDisablingRadioButton(QtWidgets.QRadioButton, QDisablingWidget):
def __init__(self, **kwds):
super().__init__(**kwds)
# On click signal handling
self.toggled.connect(self.updateSlaveStatus)
Finally, when I use the classes I need to create object like that:
disablingRadioBut = QWidgets.QDisablingRadioButton(text="My button",
parent=self,
isInMutexGroup=True)
I.e I must use keywords explicitly so that each constructors will eat the kewords the use/know.
Thanks to this approach I have maximum reusability of my extension class.
I got this solution here:
http://pyqt.sourceforge.net/Docs/PyQt5/multiinheritance.html
And more details here:
http://rhettinger.wordpress.com/2011/05/26/super-considered-super/
A very nice article!
class Parent():
def __init__(self):
self.child = Child()
class Child():
def __init__(self):
# get Parent instance
self.parent = self.Instantiator()
I know this isn't proper encapsulation but for interest's sake...
Given a "Parent" class that instantiates a "Child" object, is it possible from within Child to return the Parent object that instantiated it? And if no, I'm curious, do any languages support this?
To answer the question, no, there's no way1 the child instance knows about any classes which contain references to it. The common2 way to handle this is:
class Parent(object):
def __init__(self):
self.child = Child()
self.child._parent = self
1 Of course, this isn't strictly true. As another commentor noted, you can extract the stack frame from the executing code within the __init__ method, and examine the f_locals dictionary for the self variable for the frame before the currently executing one. But this is complicated, and prone to error. Highly unrecommended.
2 A slightly better way to handle this (depending on the specific needs of the program) might be to require the parent to pass itself to the child, like so:
class Parent(object):
def __init__(self):
self.child = Child(self)
class Child(object):
def __init__(self, parent):
self._parent = parent
Here's a reasonably-simple metaclass solution to the problem:
import functools
class MetaTrackinits(type):
being_inited = []
def __new__(cls, n, b, d):
clob = type.__new__(cls, n, b, d)
theinit = getattr(clob, '__init__')
#functools.wraps(theinit)
def __init__(self, *a, **k):
MetaTrackinits.being_inited.append(self)
try: theinit(self, *a, **k)
finally: MetaTrackinits.being_inited.pop()
setattr(clob, '__init__', __init__)
def Instantiator(self, where=-2):
return MetaTrackinits.being_inited[where]
setattr(clob, 'Instantiator', Instantiator)
return clob
__metaclass__ = MetaTrackinits
class Parent():
def __init__(self):
self.child = Child()
class Child():
def __init__(self):
self.parent = self.Instantiator()
p = Parent()
print p
print p.child.parent
a typical output, depending on the platform, will be something like
<__main__.Parent object at 0xd0750>
<__main__.Parent object at 0xd0750>
You could obtain a similar effect (in 2.6 and later) with a class decorator, but then all classes needing the functionality (both parent and children ones) would have to be explicitly decorated -- here, they just need to have the same metaclass, which may be less intrusive thanks to the "module-global __metaclass__ setting" idiom (and the fact that metaclasses, differently from class-decorations, also get inherited).
In fact, this is simple enough that I would consider allowing it in production code, if the need for that magical "instantiator" method had a proven business basis (I would never allow, in production code, a hack based on walking the stack frames!-). (BTW, the "allowing" part comes from the best-practice of mandatory code reviews: code changes don't get into the trunk of the codebase without consensus from reviewers -- this how typical open source projects work, and also how we always operate at my employer).
Here's an example based off of some of Chris B.'s suggestions to show how absolutely terrible it would be to inspect the stack:
import sys
class Child(object):
def __init__(self):
# To get the parent:
# 1. Get our current stack frame
# 2. Go back one level to our caller (the Parent() constructor).
# 3. Grab it's locals dictionary
# 4. Fetch the self instance.
# 5. Assign it to our parent property.
self.parent = sys._getframe().f_back.f_locals['self']
class Parent(object):
def __init__(self):
self.child = Child()
if __name__ == '__main__':
p = Parent()
assert(id(p) == id(p.child.parent))
Sure that'll work, but just never try to refactor it into a seperate method, or create a base class from it.
you could* try to use the traceback module, just to prove a point.
**Don't try this at home, kids*
This can be done in python with metaclasses.