Re: Composition instead of inheritance

Discussion in 'Python' started by Carl Banks, Apr 28, 2011.

  1. Carl Banks

    Carl Banks Guest

    On Thursday, April 28, 2011 10:15:02 AM UTC-7, Ethan Furman wrote:
    > For anybody interested in composition instead of multiple inheritance, I
    > have posted this recipe on ActiveState (for python 2.6/7, not 3.x):
    >
    > http://code.activestate.com/recipes/577658-composition-of-classes-instead-of-multiple-inherit/
    >
    > Comments welcome!


    That's not what we mean by composition. Composition is when one object calls upon another object that it owns to implement some of its behavior. Often used to model a part/whole relationship, hence the name.

    The sorts of class that this decorator will work for are probably not the ones that are going to have problems cooperating in the first place. So youmight as well just use inheritance; that way people trying to read the code will have a common, well-known Python construct rather than a custom decorator to understand.

    If you want to enforce no duplication of attributes you can do that, such as with this untested metaclass:

    class MakeSureNoBasesHaveTheSameClassAttributesMetaclass(type):
    def __new__(metatype,name,bases,dct):
    u = collections.Counter()
    for base in bases:
    for key in base.__dict__.keys():
    u[key] += 1
    for key in dct.keys():
    u[key] += 1
    if any(u[key] > 1 for key in u.keys()):
    raise TypeError("base classes and this class share some class attributes")
    return type.__new__(metatype,name,bases,dct)


    Carl Banks
     
    Carl Banks, Apr 28, 2011
    #1
    1. Advertising

  2. Carl Banks

    Ethan Furman Guest

    Carl Banks wrote:
    > That's not what we mean by composition. Composition is when one object
    > calls upon another object that it owns to implement some of its behavior.
    > Often used to model a part/whole relationship, hence the name.


    Hmmm. Okay -- any ideas for a better term? Something that describes
    taking different source classes and fusing them into a new whole,
    possibly using single-inheritance... Frankenstein, maybe? ;)


    > The sorts of class that this decorator will work for are probably not
    > the ones that are going to have problems cooperating in the first place.
    > So you might as well just use inheritance; that way people trying to read
    > the code will have a common, well-known Python construct rather than a
    > custom decorator to understand.


    From thread 'python and super' on Python-Dev:
    Ricardo Kirkner wrote:
    > I'll give you the example I came upon:
    >
    > I have a TestCase class, which inherits from both Django's TestCase
    > and from some custom TestCases that act as mixin classes. So I have
    > something like
    >
    > class MyTestCase(TestCase, Mixin1, Mixin2):
    > ...
    >
    > now django's TestCase class inherits from unittest2.TestCase, which we
    > found was not calling super.


    This is the type of situation the decorator was written for (although
    it's too simplistic to handle that exact case, as Ricardo goes on to say
    he has a setUp in each mixin that needs to be called -- it works fine
    though if you are not adding duplicate names).

    ~Ethan~
     
    Ethan Furman, Apr 29, 2011
    #2
    1. Advertising

  3. Carl Banks

    MRAB Guest

    On 29/04/2011 02:43, Ethan Furman wrote:
    > Carl Banks wrote:
    >> That's not what we mean by composition. Composition is when one object
    > > calls upon another object that it owns to implement some of its

    > behavior.
    > > Often used to model a part/whole relationship, hence the name.

    >
    > Hmmm. Okay -- any ideas for a better term? Something that describes
    > taking different source classes and fusing them into a new whole,
    > possibly using single-inheritance... Frankenstein, maybe? ;)
    >

    [snip]
    Fusing/fusion? Compounding?
     
    MRAB, Apr 29, 2011
    #3
  4. Carl Banks

    James Mills Guest

    On Fri, Apr 29, 2011 at 11:43 AM, Ethan Furman <> wrote:
    > Hmmm. Okay -- any ideas for a better term?  Something that describestaking
    > different source classes and fusing them into a new whole, possibly using
    > single-inheritance... Frankenstein, maybe?  ;)


    I'd have to say that this is typical of MixIns

    cheers
    James

    --
    -- James Mills
    --
    -- "Problems are solved by method"
     
    James Mills, Apr 29, 2011
    #4
  5. Carl Banks

    John Nagle Guest

    On 4/28/2011 3:35 PM, Carl Banks wrote:
    > On Thursday, April 28, 2011 10:15:02 AM UTC-7, Ethan Furman wrote:
    >> For anybody interested in composition instead of multiple
    >> inheritance, I have posted this recipe on ActiveState (for python
    >> 2.6/7, not 3.x):
    >>
    >> http://code.activestate.com/recipes/577658-composition-of-classes-instead-of-multiple-inherit/
    >>
    >>
    >>

    Comments welcome!
    >
    > That's not what we mean by composition. Composition is when one
    > object calls upon another object that it owns to implement some of
    > its behavior. Often used to model a part/whole relationship, hence
    > the name.


    The distinction isn't that strong in Python, where an object
    can't be part of another object. Object fields are references, not
    the objects themselves.

    In C++, you really can have an object as a field of an enclosing
    object. The inner object's destructor will be called first.
    Destructors and ownership tend not to be too important in Python,
    because storage management is automatic.

    John Nagle
     
    John Nagle, Apr 29, 2011
    #5
  6. Ben Finney wrote:
    > Ethan Furman <> writes:
    >
    >
    >> Carl Banks wrote:
    >>
    >>> That's not what we mean by composition. Composition is when one
    >>> object calls upon another object that it owns to implement some of
    >>> its behavior. Often used to model a part/whole relationship, hence
    >>> the name.
    >>>

    >> Hmmm. Okay -- any ideas for a better term? Something that describes
    >> taking different source classes and fusing them into a new whole,
    >> possibly using single-inheritance... Frankenstein, maybe? ;)
    >>

    >
    > (Remember that Frankenstein was not the monster, but the scientist.)
    >
    > “Hybrid�
    >
    >

    Actualy this story is about the villagers being the monsters :eek:)

    JM
     
    Jean-Michel Pichavant, Apr 29, 2011
    #6
  7. Carl Banks

    Ethan Furman Guest

    James Mills wrote:
    > On Fri, Apr 29, 2011 at 11:43 AM, Ethan Furman <> wrote:
    >> Hmmm. Okay -- any ideas for a better term? Something that describes taking
    >> different source classes and fusing them into a new whole, possibly using
    >> single-inheritance... Frankenstein, maybe? ;)

    >
    > I'd have to say that this is typical of MixIns


    Yes, but it's designed to be used when Mixins fail because of MI issues
    (see my reply to Carl for an example).

    Maybe Integrate?

    ~Ethan~
     
    Ethan Furman, Apr 29, 2011
    #7
  8. Carl Banks

    Ian Kelly Guest

    On Fri, Apr 29, 2011 at 3:09 PM, Carl Banks <> wrote:
    > Here is my advice on mixins:
    >
    > Mixins should almost always be listed first in the bases.  (The only exception is to work around a technicality.  Otherwise mixins go first.)
    >
    > If a mixin defines __init__, it should always accept self, *args and **kwargs (and no other arguments), and pass those on to super().__init__.  Same deal with any other function that different sister classes might define in varied ways (such as __call__).


    Really, *any* class that uses super().__init__ should take its
    arguments and pass them along in this manner. This applies to your
    base classes as well as your mixins. It's okay to take keyword
    arguments as well, but you have to be careful to pass them on exactly
    as you received them. Reason being that you can't pragmatically
    predict which __init__ method will be invoked next by the super call,
    which means that you can't predict which arguments will be needed for
    that call, so you just have to pass all of them along.

    > A mixin should not accept arguments in __init__.  Instead, it should burden the derived class to accept arguments on its behalf, and set attributes before calling super().__init__, which the mixin can access.


    Ugh. This breaks encapsulation, since if I ever need to add an
    optional argument, I have to add handling for that argument to every
    derived class that uses that mixin. The mixin should be able to
    accept new optional arguments without the derived classes needing to
    know about them.

    > If you insist on a mixin that accepts arguments in __init__, then it should should pop them off kwargs.  Avoid using positional arguments, and never use named arguments.  Always go through args and kwargs.


    Theoretically this would break if you had two mixins accepting the
    same argument, but I can't think of an actual case where that might
    happen.

    Cheers,
    Ian
     
    Ian Kelly, Apr 29, 2011
    #8
  9. Carl Banks

    Ian Kelly Guest

    On Fri, Apr 29, 2011 at 5:54 PM, Carl Banks <> wrote:
    >> Really, *any* class that uses super().__init__ should take its
    >> arguments and pass them along in this manner.

    >
    > If you are programming defensively for any possible scenario, you might try this (and you'd still fail).
    >
    > In the real world, certain classes might have more or less probability tobe used in a multiple inheritance situations, and programmer needs to weigh the probability of that versus the loss of readability.  For me, exceptwhen I'm designing a class specifically to participate in MI (such as a mixin), readability wins.


    Agreed. Actually, my preferred solution is to not use super at all.
    It's so rarely needed (i.e. diamond inheritance situations) that it's
    usually not worth it to jump through the hoops it creates, so I prefer
    to call the base class methods explicitly.

    For pure base-class + mixin design, you should not have any diamond
    inheritance situations, so super should not really be necessary.

    > If you merely mean DRY, then I'd say this doesn't necessarily add to it.  The derived class has a responsibility one way or another to get the mixin whatever initializers it needs.


    I mean the difference in terms of maintenance between this:

    class Derived1(Mixin1, Base):
    def __init__(self, mixin_arg1, mixin_arg2, *args, **kwargs):
    self.mixin_arg1 = mixin_arg1
    self.mixin_arg2 = mixin_arg2
    super(Derived, self).__init__(*args, **kwargs)

    and simply doing this:

    class Derived2(Mixin2, Base):
    def __init__(self, *args, **kwargs):
    super(Derived, self).__init__(*args, **kwargs)

    In both cases we are passing the arguments in to the mixin. In the
    former case, if we later decide to add mixin_arg3, then we have to
    also add it to the Derived1.__init__ signature and then add a line to
    set the attribute. In the latter case, adding mixin_arg3 has no
    effect on the Derived2 initializer at all, because it passes through
    transparently in the kwargs.

    Cheers,
    Ian
     
    Ian Kelly, Apr 30, 2011
    #9
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. -
    Replies:
    1
    Views:
    493
    John C. Bollinger
    Apr 11, 2005
  2. Code4u
    Replies:
    9
    Views:
    2,822
  3. Gary Wessle

    inheritance and composition

    Gary Wessle, Nov 16, 2006, in forum: C++
    Replies:
    3
    Views:
    309
  4. Replies:
    8
    Views:
    568
    James Kanze
    Jul 29, 2007
  5. Ethan Furman

    Composition instead of inheritance

    Ethan Furman, Apr 28, 2011, in forum: Python
    Replies:
    2
    Views:
    262
    Alan Meyer
    May 2, 2011
Loading...

Share This Page