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

N

Nick

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:

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.
 
A

alex23

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


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.
 
G

Gabriel Genellina

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:

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
 
M

Michele Simionato

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.
 
N

Nick

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
 
G

Gabriel Genellina

En Tue, 31 Mar 2009 05:16:47 -0300, Steven D'Aprano
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.
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.
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,995
Messages
2,570,236
Members
46,825
Latest member
VernonQuy6

Latest Threads

Top