An inheritance question: getting the name of the "one up" class

Discussion in 'Python' started by Nick, Mar 31, 2009.

  1. Nick

    Nick Guest

    I've got a collection of classes describing animals, part of which looks
    like:

    class Animal(object):
    def __init__(self):
    self.pet = False
    self.edible = False
    self.legs = 0
    self.sound = None
    self.name = self.__class__.__name__.lower()

    class Mammal(Animal):
    def __init__(self):
    Animal.__init__(self)
    self.legs = 4

    class Primate(Mammal):
    def __init__(self):
    Mammal.__init__(self)
    self.legs = 2

    class Human(Mammal):
    def __init__(self):
    Primate.__init__(self)
    self.sound = "Hey, I can talk!"

    I want to add a "pedigree" function to Animal so that I can have:

    >>> h = Human()
    >>> h.pedigree()

    human < primate < mammal < animal
    >>>


    I've been thinking about something like:
    def pedigree(self):
    n = self.name
    while n != 'object' # base class of Animal
    print n,
    n = Well, this is where I'm stuck. super(???,???).???
    print

    Oh, and while the gurus are at it, what would be the advantage (if any) of
    changing, say
    Primate.__init__(self)
    to
    super(Human, self).__init__()

    Thanks, all,

    Nick.
     
    Nick, Mar 31, 2009
    #1
    1. Advertising

  2. Nick

    alex23 Guest

    On Mar 31, 1:13 pm, "Nick" <> wrote:
    > I want to add a "pedigree" function to Animal so that I can have:
    >
    > >>> h = Human()
    > >>> h.pedigree()

    >
    > human < primate < mammal < animal


    class Animal(object):
    @classmethod
    def pedigree(cls):
    return [c.__name__ for c in cls.mro() if c is not object]

    class Mammal(Animal): pass
    class Primate(Mammal): pass
    class Human(Primate): pass

    >>> h = Human()
    >>> h.pedigree()

    ['Human', 'Primate', 'Mammal', 'Animal']
    >>> ' > '.join(h.pedigree())

    'Human > Primate > Mammal > Animal'


    As long as you're using single inheritance in the way you've outlined
    here, you should be able to pull the information out of the class' .mro
    () method, which returns the list of classes that an object will
    resolve method calls against. If you're using multiple inheritance,
    you will need to look into the inspect module or read through the
    __bases__ attribute on the class.

    > Oh, and while the gurus are at it, what would be the advantage (if any) of
    > changing, say
    >    Primate.__init__(self)
    > to
    >    super(Human, self).__init__()


    While super() has other advantages, the most immediate for you would
    be the ability to change the parent class of an object at the class
    definition without having to modify anything in that class's __init__.
    For eg, if you decided to add another class - MissingLink - between
    Primate & Human, using super() you'd only have to change the class
    definiton to read 'class Human(MissingLink):' and super would call the
    right initialiser, whereas by using Primate.__init__ within
    Human.__init__ you'd have to modify the class in two places.
     
    alex23, Mar 31, 2009
    #2
    1. Advertising

  3. En Tue, 31 Mar 2009 00:13:44 -0300, Nick <>
    escribió:

    > I've got a collection of classes describing animals, part of which looks
    > like:
    >
    > class Animal(object):
    > def __init__(self):
    > self.pet = False
    > self.edible = False
    > self.legs = 0
    > self.sound = None
    > self.name = self.__class__.__name__.lower()
    >
    > class Mammal(Animal):
    > class Primate(Mammal):
    > class Human(Mammal):


    (shouldn't be Primate?)

    > I want to add a "pedigree" function to Animal so that I can have:
    >
    >>>> h = Human()
    >>>> h.pedigree()

    > human < primate < mammal < animal


    The subject says `getting the name of the "one up" class` but Python
    allows for multiple inheritance, so you could have several "one up"
    classes.
    Classes have a mro ("method resolution order") that linearizes the
    inheritance tree in a very specific way. In the case of single
    inheritance, it returns the sequence of base clases, from last to first
    (object).

    Human.mro() yields:
    [<class 'a.Human'>, <class 'a.Primate'>, <class 'a.Mammal'>, <class
    'a.Animal'>, <type 'object'>]

    We have to omit the last element and take the __name__ of each class. And
    this is clearly a class method: it doesn't depend on any instance. Let's
    add this to the Animal class:

    @classmethod
    def pedigree(cls):
    return ' < '.join(base.__name__ for base in cls.mro()[:-1])

    Human.pedigree() returns:
    Human < Primate < Mammal < Animal

    > I've been thinking about something like:
    > def pedigree(self):
    > n = self.name
    > while n != 'object' # base class of Animal
    > print n,
    > n = Well, this is where I'm stuck. super(???,???).???
    > print


    You can't use self.name here -- I assume you want *class* relationships,
    so you can't use instance data, ok?
    Each class has a __bases__ attribute, and assuming you only have single
    inheritance, the "one up" class is __bases__[0] -- you could write
    pedigree() now using __bases__[0].
    (But I'd let Python do the hard work and use mro() instead...)

    > Oh, and while the gurus are at it, what would be the advantage (if any)
    > of changing, say
    > Primate.__init__(self)
    > to
    > super(Human, self).__init__()


    None, if you use single inheritance everywhere.

    super is very tricky; see:
    http://fuhm.net/super-harmful/
    and
    http://www.artima.com/weblogs/viewpost.jsp?thread=236275

    --
    Gabriel Genellina
     
    Gabriel Genellina, Mar 31, 2009
    #3
  4. On Tue, 31 Mar 2009 01:29:50 -0300, Gabriel Genellina wrote:

    >> Oh, and while the gurus are at it, what would be the advantage (if any)
    >> of changing, say
    >> Primate.__init__(self)
    >> to
    >> super(Human, self).__init__()

    >
    > None, if you use single inheritance everywhere.



    But there's no disadvantage to using super with single inheritance (and
    new-style classes).



    > super is very tricky; see:
    > http://fuhm.net/super-harmful/
    > and
    > http://www.artima.com/weblogs/viewpost.jsp?thread=236275



    As I understand it, the trickiness only comes about when you have diamond
    diagrams in your MRO.



    --
    Steven
     
    Steven D'Aprano, Mar 31, 2009
    #4
  5. On Mar 31, 5:13 am, "Nick" <> wrote:
    > Oh, and while the gurus are at it, what would be the advantage (if any) of
    > changing, say
    >    Primate.__init__(self)
    > to
    >     super(Human, self).__init__()


    What others said. In Python 3.0 you would have a bigger advantage,
    since you can just
    write

    super().__init__()

    without repetition.
    I normally use super, because it is the recommended solution by Guido.
    This is not to say that I am perfectly happy, by my gripe is more
    against
    multiple inheritance than against super itself.
     
    Michele Simionato, Mar 31, 2009
    #5
  6. Nick

    Nick Guest

    Thanks for the replies. This has given me some incentive to start looking at
    Python 3. Oh, and thanks for the articles on super().

    Nick
     
    Nick, Mar 31, 2009
    #6
  7. En Tue, 31 Mar 2009 05:16:47 -0300, Steven D'Aprano
    <> escribió:

    > On Tue, 31 Mar 2009 01:29:50 -0300, Gabriel Genellina wrote:
    >
    >>> Oh, and while the gurus are at it, what would be the advantage (if any)
    >>> of changing, say
    >>> Primate.__init__(self)
    >>> to
    >>> super(Human, self).__init__()

    >>
    >> None, if you use single inheritance everywhere.

    >
    > But there's no disadvantage to using super with single inheritance (and
    > new-style classes).


    It's ok *if* you follow the guidelines at the end of the "harmful"
    document.

    >> super is very tricky; see:
    >> http://fuhm.net/super-harmful/
    >> and
    >> http://www.artima.com/weblogs/viewpost.jsp?thread=236275

    >
    > As I understand it, the trickiness only comes about when you have diamond
    > diagrams in your MRO.


    With multiple inheritance, you *always* have a diamond diagram - every
    class inherits from object.

    --
    Gabriel Genellina
     
    Gabriel Genellina, Mar 31, 2009
    #7
    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. E11
    Replies:
    1
    Views:
    4,897
    Thomas Weidenfeller
    Oct 12, 2005
  2. Marc E
    Replies:
    8
    Views:
    406
    Thomas Hawtin
    Nov 28, 2005
  3. Replies:
    3
    Views:
    8,536
    ducnbyu
    Nov 22, 2006
  4. johnsonlau
    Replies:
    1
    Views:
    787
    Kai-Uwe Bux
    Jul 21, 2008
  5. Kyle Schmitt
    Replies:
    11
    Views:
    177
    Robert Klemme
    Sep 26, 2008
Loading...

Share This Page