Python Forum

Full Version: [SOLVED] [newbie] Why call super()? When to use parent?
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
Hello,

I'm reading a book on wxPython, and have a couple of newbie questions:

1. Why is a call to super() required? When commented out, Python ain't happy

2. When/why should I call an instance with (self/parent), eg."panel = MyPanel(self)" vs. "frame = MyFrame()"?

Thank you.

import wx

class MyPanel(wx.Panel):
	def __init__(self, parent):
		#required, or "RuntimeError: super-class __init__() of type MyPanel was never called"
		#who is the parent? frame?
		super().__init__(parent)
		button = wx.Button(self, label='Press Me')

class MyFrame(wx.Frame):
	def __init__(self):
		#RuntimeError: super-class __init__() of type MyFrame was never called
		super().__init__(None, title='Hello World')
		#what is self? parent? What for?
		panel = MyPanel(self)
		self.Show()

if __name__ == '__main__':
	app = wx.App()
	frame = MyFrame()
	app.MainLoop()
Question 1: Why do I have to call super().__init__()

This is a pared down example:
mport wx

class MyFrame(wx.Frame):
    pass

print(*MyFrame.__mro__, sep="\n")
Run this code and it prints the Method Resolution Order, the class path that is followed when looking for attributes or calling methods. This is what gets printed.
Output:
<class '__main__.MyFrame'> <class 'wx._core.Frame'> <class 'wx._core.TopLevelWindow'> <class 'wx._core.NonOwnedWindow'> <class 'wx._core.Window'> <class 'wx._core.WindowBase'> <class 'wx._core.EvtHandler'> <class 'wx._core.Object'> <class 'wx._core.Trackable'> <class 'sip.wrapper'> <class 'sip.simplewrapper'> <class 'object'>
Calling super().__init__() in the MyFrame.__init__() method calls wx._core.Frame.__init__(). That method in turn likely calls wx._core.TopLevelWindow.__init__() which probably calls wx._core.NonOwnedWindow, and so on and so on. All those method probably perform some important steps in initializing a Frame object. If you didn't call super().__init__(), none of that code would be executed.

Question 2: When should I pass an argument when I create an object.

When it is needed.

I'm going to rewrite your code to make the following discussion a bit less confusing.
class MyFrame(wx.Frame):
    def __init__(self):
        super().__init__(None, title='Hello World')
        parent_frame= self
        MyPanel(parent_frame)
        self.Show()
When MyFrame.__init__() calls MyPanel(parent_frame) it does two things. It creates a new MyPanel object, and it calls MyPanel.__init__(parent_frame)

In MyPanel.__init__(self, parent), self is the new MyPanel object, and parent is the parent_frame argument. The first argument of an instance method is the instance of the object that provides the context for the method. By convention this is always called "self". Arguments passed when the object was created appear after self.

So how do you know when you need to pass arguments to the __init__() method? You look at the code or your read the documentation. You wrote MyFrame, so you can look at your code and see if you need to pass any arguments.
class MyPanel(wx.Panel):
    def __init__(self, parent):
You can clearly see that parent is a required argument, so any time you create a MyPanel object you need to pass an argument for parent.

But what about here?
class MyFrame(wx.Frame):
    def __init__(self):
        #RuntimeError: super-class __init__() of type MyFrame was never called
        super().__init__(None, title='Hello World')
There are no arguments following self in MyFrame.__init__(self), so you cannot pass an argument.

You could rewrite your code like this:
class MyFrame(wx.Frame):
    def __init__(self, parent=None):
        #RuntimeError: super-class __init__() of type MyFrame was never called
        super().__init__(parent, title='Hello World')
Now you have the option of passing a "parent" argument when you create a MyFrame. What does the parent argument do? That is where you need to look at the documentation.

https://docs.wxpython.org/wx.Frame.html
Quote:__init__ (self, parent, id=ID_ANY, title=””, pos=DefaultPosition, size=DefaultSize, style=DEFAULT_FRAME_STYLE, name=FrameNameStr)

Constructor, creating the window.

Parameters:
parent (wx.Window) – The window parent. This may be, and often is, None. If it is not None, the frame will be minimized when its parent is minimized and restored when it is restored (although it will still be possible to minimize and restore just this frame itself).
For a Frame, the parent is an optional argument If provided, the child frame is minimized and restored when the parent is minimized and restored.
Thanks much.

--
Edit: A call to a class' __init__ isn't required, but if it's a derived class and you do call it for some reason, you must also call its parent's __init__ or Python triggers an error.

There might be a reason why Python doesn't call the parent's __init__ automatically, even when the user has nothing to add to it.

class MyPanel(wx.Panel):
	"""
	def __init__(self, parent):
		#required, or "RuntimeError: super-class __init__() of type MyPanel was never called"
		#who is the parent? frame?
		super().__init__(parent)
		button = wx.Button(self, label='Press Me')
	"""
	pass
(Feb-09-2025, 02:16 PM)Winfried Wrote: [ -> ]but if it's a derived class and you do call it for some reason, you must also call its parent's __init__ or Python triggers an error.
This is not true.
class Parent:
    def __init__(self):
        print("Parent init called")

class Child(Parent):
    def __init__(self):
        print('Child init called')

c = Child() # no error is triggered
print(c)
Output:
Child init called <__main__.Child object at 0x7fce955045f0>
The point is that if you initialize derived objects without calling the parent's init method, you may end up with objects in an inconsistent state. For example the parent's class methods may assume that the object has a member spam, and if you don't call the parent's init method, this member may be missing because it is not initialized.
(Feb-09-2025, 02:16 PM)Winfried Wrote: [ -> ]There might be a reason why Python doesn't call the parent's __init__ automatically, even when the user has nothing to add to it.
I think there is a reason: it enables you to completely overwrite the object's initialization, which would be impossible if the parent's __init__ method was called automatically.
Thanks. So Super() doesn't have to call its parent, but some code may require it and trigger an error otherwise:

import wx

class MyPanel(wx.Panel):
	def __init__(self, parent):
		super().__init__(parent)
		button = wx.Button(self, label='Press Me')
	
class MyFrame(wx.Frame):
	def __init__(self):
		#RuntimeError: super-class __init__() of type MyFrame was never called
		super().__init__(None, title='Hello World')
		panel = MyPanel(self)
		self.Show()

if __name__ == '__main__':
	app = wx.App()
	frame = MyFrame()
	app.MainLoop()