Confused about class relationships

John O'Hagan mail at johnohagan.com
Mon Dec 1 06:28:14 CET 2008


On Sat, 29 Nov 2008, Carl Banks wrote:
> On Nov 26, 11:20 pm, John O'Hagan <resea... at johnohagan.com> wrote:
[...]
> >
> > class Bar(list):
> >
> >         def __init__(self, a_bar, args, engine):
> >                 list.__init__ (self, a_bar)
> >                 self[:] = a_bar        
> >                 self.args = args
> >                 self.engine = engine
> >                 #more instance attributes...
> >
> >         #methods...
> >
> > class Engine:
> >
> >         def __init__(self, args):
> >                 self.args = args                        
> >                 #more instance attributes...
> >
> >         def bar_builder(self):
> >                 #body of method generates lists...
> >                 yield Bar([generated_list], args, self)
> >
> >         #more methods...
> >
> > #(other stuff...)
> >
> > def main(args):
> >
> >             engine = Engine(args)
> >             bars = engine.bar_builder()
> >             for a_bar in bars:
> >                 #play the music!...
> >
> > While this works (to my surprise!) and solves the problem which motivated
> > it (i.e. Engine instances need to pass some attributes to Bar instances
> > ), it seems too convoluted. Should one class inherit the other?
>
> No.  (I wonder if you meant, "Should one class reference the other?",
> as in, "Should Engines only reference bars or Bars only reference
> engines, but not both?", in which case the answer is a non-commital,
> "It depends.")
>
> Inheritance is not something you do because object A wants to access
> the attributes/properties/etc. of B.  Actually, that is something that
> happens pretty often and when it does, there's a couple things you
> should think about:
>
> 1. How you want A to access the attributes of B.  Should you just let
> A poke around in B, or should you define methods of B for A to call,
> and those methods access the internals of B?  It's a judgment call
> most of the time.
>
> 2. Whether some behavior of B ought to be defined as part of A's class
> instead, or vice versa.  There is sometimes ambiguity over what class
> a method that uses the attributes of two different objects should
> belong to.
>
> Inheritance isn't something you need to think about here.
>
> Inheritance is something you consider when you have two objects, A and
> B, that should act very similar or the same in certain situations.
> Engines and Bars don't seem to share any behavior at all.  Contrast
> this to Bars and lists, which do share behavior.  x[1] does pretty
> much the same thing whether x is a Bar or a list, I'd imagine, so
> there's reason for an inheritance relationship there.
>
> > If so, which way
> > around? Or is it fine as is?
>
> One thing you might want to consider is whether Engine instance could
> be simply passed into the Bar's play method (or whatever other method
> accesses the Engine attributes), and whether the Engine needs to be
> involved in generating bars at all.  For instance:
>
>
> class Bar(list):
>     def __init__(self, a_bar, args):
>         list.__init__(self, a_bar)
>         self[:] = a_bar
>         self.args = args
>         # etc.
>     def play(self, engine):
>         use(engine.time_signature).somehow()
>         # instead of use(self.engine.time_signature).somehow()
>
>
> def bar_builder(self,args):
>     # plain function, not part of Engine class
>     # or perhaps a method of some other class
>     yield Bar([generated_list],args)
>
>
> def main():
>     engine = Engine(args)
>     bars = bar_builder(self,args)
>     for a_bar in bars:
>         a_bar.play(engine)
>
>
> One benefit of doing it this way is that you've freed Bars and Engines
> from each other.  Conceivably you could create a second engine object
> (maybe of a different type altogether), and play the very same Bar
> objects with that engine instead.

Thanks for such a detailed reply...I actually had bar_builder as  a plain 
function originally, but because I didn't know how to pass attributes around 
like you have above, I was using globals to do it and was trying to solve 
that by classing everything in sight. Although the program doesn't work quite 
as you have deduced above, I can use the approach you suggest to simplify it 
immensely. (I hope.)
>
> > I'm hoping this is a common trap I've fallen into; I just haven't been
> > able to get my head around it. (I'm a musician...)
>
> Well I think it looks pretty good for a musician newbie.  There's a
> few organizational decisions I'd make differently, but overall it's
> clean and readable and not too complicated how you did it.  At least
> not what you've showed us. :)
>
[...]
Believe me, the whole thing is more complicated and messy, but you don't want 
to see my dirty laundry! :)

Regards,

john





More information about the Python-list mailing list