[Tutor] Multiple inheritance

Phil phillor9 at gmail.com
Fri May 14 06:58:20 EDT 2021


On 14/5/21 8:31 pm, Alan Gauld via Tutor wrote:
> You can't. Ignore the MI issue and consider Meter as a
> stand-alone class. You have defined its __init__() as
> taking an argument. So you must theefore provide that
> argument.

Thank you Alan, I think this is what's required. Still, m = Meter(200) 
and then print(m.angle) doesn't generate an error but doesn't print 
anything as far as I can tell. Also, how do I tell the MyForm class 
methods (update() and OnPaint()) that the variables angle etc belong to 
the Meter class? That's why I was attempting to inherit the Meter class.

import wx
import math

class Meter:
     def __init__(self, start_x):
         self.angle = 180  # start with the pointer pointing to the left
         self.rad = 0
         self.start_x = start_x  # the starting point of the pointer
         self.start_y = 200
         self.length = 50  # the length of the pointer
         self.inc_amount = 5

class MyForm(wx.Frame):
     def __init__(self):
         wx.Frame.__init__(self, None, wx.ID_ANY, "Meter Test", 
size=(300, 300))

         #Meter.__init__(self, 200)#Meter.start_x)

         m = Meter(200)
         print(m.angle)

         '''
         These variables have been moved to the meter class

         self.angle = 180  # start with the pointer pointing to the left
         self.rad = 0
         self.start_x = 200  # the starting point of the pointer
         self.start_y = 200
         self.length = 50  # the length of the pointer
         self.inc_amount = 5
         '''
         self.InitUI()

     def InitUI(self):

         self.Bind(wx.EVT_PAINT, self.OnPaint)

         panel = wx.Panel(self, wx.ID_ANY)

         self.timer = wx.Timer(self)
         self.Bind(wx.EVT_TIMER, self.update, self.timer)
         self.timer.Start(100)

     def update(self, event):
         if m.angle == 360:
             Meter.inc_amount *= -1

         Meter.angle += Meter.inc_amount

         if self.angle == 180:
             Meter.inc_amount *= -1

         Meter.rad = (Meter.angle * math.pi / 180)

         self.Refresh()

     def OnPaint(self, e):
         dc = wx.PaintDC(self)

         # Create graphics context
         gc = wx.GraphicsContext.Create(dc)

         if gc:
             gc.SetPen(wx.RED_PEN)
             path = gc.CreatePath()

             path.AddArc(Meter.start_x, Meter.start_y, 60, 
math.radians(180),
                         math.radians(0), 1)
             path.AddLineToPoint(140, self.start_y)
             #gc.StrokePath(path)
             gc.DrawPath(path)

             x = int(Meter.start_x + math.cos(Meter.rad) * Meter.length)
             y = int(Meter.start_y + math.sin(Meter.rad) * Meter.length)

             dc.DrawLine(Meter.start_x, Meter.start_y, x, y)


if __name__ == "__main__":
     app = wx.App()
     frame = MyForm().Show()
     app.MainLoop()


>
> class Meter():
>       def __init__(self, start_x):
>           self.angle = 180  # start with the pointer pointing to the left
>           self.rad = 0
>           self.start_x = start_x  # the starting point of the pointer
>           self.start_y = 200
>           self.length = 50  # the length of the pointer
>           self.inc_amount = 5
>
> start_x inside Meter does not exist until after init() is executed.
> And init requires that you provide a value. This is true regardless
> of whether you create a stand-alone instance of Meter or if you
> inherit from Meter.
>
> You could define a default value:
>
> class Meter():
>       def __init__(self, start_x=0):...
>
> That would allow you to call init without a start_x and ensure
> it always had some value. But you can never change startx unless
> you pass a value into init() startx does not exist until after
> init() has been called.
>
> Incidentally, I doubt very much whether you really want to
> use MI here.  A Form is very unlikely to be a Meter. It may
> contain a meter but it is not a Meter itself, and inheritance
> implements an "is-a" relationship.
>
> The very fact tat your Meter class has no methods other than
> init() suggests it is merely a data container. As such it would
> be better to pass a Meter instance into the form init() and store
> it as an instance attribute of the form.
>
> MI is a very powerful and useful tool but it brings with it a
> host of added complexity and should only be used when it is
> genuinely needed. In all other cases containment and delegation
> are usually better options.
>

-- 
Regards,
Phil



More information about the Tutor mailing list