[Tutor] Multiple inheritance

Alan Gauld alan.gauld at yahoo.co.uk
Fri May 14 06:31:29 EDT 2021


On 14/05/2021 10:27, Phil wrote:
> On 14/5/21 5:04 pm, Cameron Simpson wrote:

>> But... Where does start_x come from? I don't see it in the arguments to
>> MyForm.__init__.
> 
> start_x is a variable in the Meter class. Maybe what I'm trying to 
> achieve is the problem? What I'd like to do is create a Meter class so 
> that I can import it into some other programme.

Thats fine, but unrelated to multiple inheritance and what's happening
here. That's just a normal class definition. but you can only pass in
arguments that are visible at the point of calling the method. You
cannot refer to instance variables before the instance has been
initialized (by __init__) and even then you need to prefix the name with
the instance 9self in this case)

>> super().method is good to finding method in a superclass. Here you need
>> to call each superclass __init__ separately with distinct arguments.
> 
> Super, from what I've read, is not really necessary. It sounds like a 
> complication that I can do without, at least for now.

super() is not really necessary in single inheritance it is
however essential in multiple inheritance or you can get
very weird cyclic behaviour and incomplete or multiple
initialization of attributes.

Always use super() in multiple inheritance cases, and its
usually better in single inheritance too, for consistency
if nothing else! super in Python2 was a bit of a mess, but
in python 3 super is clean and effective.

> I retyped that line in Visual Studio (Pylance), just in case, and the 
> error is "invalid character in identifier". However, selecting __init__ 
> from the suggestion list solved that problem. Start_x generates a "not 
> defined error". As above, start_x is a Meter class variable. How do I 
> get around that problem?

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.

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.

-- 
Alan G
Author of the Learn to Program web site
http://www.alan-g.me.uk/
http://www.amazon.com/author/alan_gauld
Follow my photo-blog on Flickr at:
http://www.flickr.com/photos/alangauldphotos




More information about the Tutor mailing list