Can I inherit member variables?

L

lm401

I'm trying to work with the following idea:

class animal:
def __init__(self, weight, colour):
self.weight = weight
self.colour = colour


class bird(animal):
def __init__(self, wingspan):
self.wingspan = wingspan
print self.weight, self.colour, self.wingspan

class fish(animal):
def __init__(self, length):
self.length = length
print self.weight, self.colour, self.length


So basically I have a base class (animal) that has certain attributes.
When animal is inherited by a specific instance, further attributes are
added, but I need to have access to the original attributes (weight,
colour). When I run my code from within the derived class, self.weight
and self.colour are not inherited (although methods are inherited as I
would have expected).

It seems from reading the newsgroups that a solution might be to
declare weight and colour as global variables in the class animal:

class animal:
pass

myanimal = animal()
myanimal.weight = 4
myanimal.colour = 'blue'

But this is not exactly what I want to do.

I'm not very experienced with OOP techniques, so perhaps what I'm
trying to do is not sensible. Does Python differ with regard to
inheritance of member variables from C++ and Java?

Thanks for any help,



Lorcan.
 
B

Benjamin Niemann

Hello,

I'm trying to work with the following idea:

class animal:
def __init__(self, weight, colour):
self.weight = weight
self.colour = colour


class bird(animal):
def __init__(self, wingspan):
self.wingspan = wingspan
print self.weight, self.colour, self.wingspan

class fish(animal):
def __init__(self, length):
self.length = length
print self.weight, self.colour, self.length


So basically I have a base class (animal) that has certain attributes.
When animal is inherited by a specific instance, further attributes are
added, but I need to have access to the original attributes (weight,
colour). When I run my code from within the derived class, self.weight
and self.colour are not inherited (although methods are inherited as I
would have expected).

You'll have to invoke the __init__ method of the superclass, this is not
done implicitly. And you probably want to add the weight and colour
attributes to your subclass in order to pass these to the animal
constructor.

class fish(animal):
def __init__(self, length, weight, colour):
animal.__init__(self, weight, colour)
self.length = length
print self.weight, self.colour, self.length


HTH
 
M

MonkeeSage

When I run my code from within the derived class, self.weight
and self.colour are not inherited (although methods are inherited as I
would have expected).

Animal is never initialized and you're not passing weight and color
into it anyway. You need something like:

class animal: # (object): # <- new-style class
def __init__(self, weight, colour):
self.weight = weight
self.colour = colour

class bird(animal):
def __init__(self, weight, color, wingspan):
#super(bird, self).__init__(weight, color) # <- new-style init
animal.__init__(self, weight, color) # <- old-style init
self.wingspan = wingspan
print self.weight, self.colour, self.wingspan

class fish(animal):
def __init__(self, weight, color, length):
#super(fish, self).__init__(weight, color)
animal.__init__(self, weight, color)
self.length = length
print self.weight, self.colour, self.length

HTH,
Jordan
 
L

LorcanM

Thanks for the reply.

I think there's a basic misunderstanding about the nature of
inheritance on my side.

What I want to do is instantiate the sub class (derived class) from
within the animal class. I then expect the sub class to have inherited
some basic properties that it knows it has (weight, colour). If I can
expand the example I gave previously to try to make this a little
clearer:

class animal:
def __init__(self, weight, colour):
self.weight = weight
self.colour = colour

def describeMyself(self, type, measurement):
if type == 'bird':
myanimal = bird(measurement)
elif type == 'fish':
myanimal = fish(measurement)

class bird(animal):
def __init__(self, wingspan):
self.wingspan = wingspan
print "I'm a bird, weight %s, colour %s, wingspan %s" %
(self.weight, self.colour, self.wingspan)

class fish(animal):
def __init__(self, length):
self.length = length
print "I'm a fish, weight %s, colour %s, length %s" % (self.weight,
self.colour, self.length)


It seems from what you say that the attributes (member variables) will
have to be passed forward explicitly like any other function call. This
of course is sensible, 'bird' or 'fish' are not tied to a specific
instance of 'animal' when they are instantiated.

Thanks for the help,


Lorcan.


Benjamin Niemann wrote:
 
G

Gabriel Genellina

At said:
class animal:
def __init__(self, weight, colour):
self.weight = weight
self.colour = colour


class bird(animal):
def __init__(self, wingspan):
self.wingspan = wingspan
print self.weight, self.colour, self.wingspan

class fish(animal):
def __init__(self, length):
self.length = length
print self.weight, self.colour, self.length


So basically I have a base class (animal) that has certain attributes.
When animal is inherited by a specific instance, further attributes are
added, but I need to have access to the original attributes (weight,
colour). When I run my code from within the derived class, self.weight
and self.colour are not inherited (although methods are inherited as I
would have expected).

You have to call the base __init__ too. If a bird is some kind of
animal, it has a weight and a colour, and you have to provide them too:

class bird(animal):
def __init__(self, weight, colour, wingspan):
animal.__init__(self, weight, colour)
self.wingspan = wingspan
print self.weight, self.colour, self.wingspan
It seems from reading the newsgroups that a solution might be to
declare weight and colour as global variables in the class animal:

You can declare them as class attributes inside animal; this way they
act like a default value for instance attributes.

class animal:
weight = 0
colour = ''
...
I'm not very experienced with OOP techniques, so perhaps what I'm
trying to do is not sensible. Does Python differ with regard to
inheritance of member variables from C++ and Java?

They are not called "member variables" but "instance attributes".
They *are* inherited [1] but you have to set their value somewhere.
Any object can hold virtually any attribute - this is *not* usually
determined by the object's class.
Base constructors ("initializer" actually) are *not* invoked
automatically, so you must call them explicitely.

Read the Python Tutorial, it's easy and will teach you a lot of
things about the language. You can read it online at
<http://docs.python.org/tut/tut.html>

[1] kinda... remember that classes don't determine the available
attributes; class attributes are inherited, and any attribute you set
on an instance will be accessible by any method of the object, even
above in the hierarchy.



Gabriel Genellina
Softlab SRL





__________________________________________________
Preguntá. Respondé. Descubrí.
Todo lo que querías saber, y lo que ni imaginabas,
está en Yahoo! Respuestas (Beta).
¡Probalo ya!
http://www.yahoo.com.ar/respuestas
 
G

Gabriel Genellina

I think there's a basic misunderstanding about the nature of
inheritance on my side.

What I want to do is instantiate the sub class (derived class) from
within the animal class. I then expect the sub class to have inherited
some basic properties that it knows it has (weight, colour). If I can
expand the example I gave previously to try to make this a little
clearer:

As an analogy: a certain animal, a given individual, is of a kind
"from birth". You don't have an abstract, unshaped, animal, that by
some kind of magic later becomes a bird, or a mammal...
When you construct an object instance, it is of a certain type from
that precise moment, and you can't change that afterwards.
So, you construct a bird, which is a kind of animal (class
inheritance is the way of modelling that "is a kind of" relationship).

Hope it becomes clearer now.



Gabriel Genellina
Softlab SRL





__________________________________________________
Preguntá. Respondé. Descubrí.
Todo lo que querías saber, y lo que ni imaginabas,
está en Yahoo! Respuestas (Beta).
¡Probalo ya!
http://www.yahoo.com.ar/respuestas
 
B

Benjamin Niemann

LorcanM said:
Thanks for the reply.

I think there's a basic misunderstanding about the nature of
inheritance on my side.

What I want to do is instantiate the sub class (derived class) from
within the animal class. I then expect the sub class to have inherited
some basic properties that it knows it has (weight, colour). If I can
expand the example I gave previously to try to make this a little
clearer:

class animal:
def __init__(self, weight, colour):
self.weight = weight
self.colour = colour

def describeMyself(self, type, measurement):
if type == 'bird':
myanimal = bird(measurement)
elif type == 'fish':
myanimal = fish(measurement)

class bird(animal):
def __init__(self, wingspan):
self.wingspan = wingspan
print "I'm a bird, weight %s, colour %s, wingspan %s" %
(self.weight, self.colour, self.wingspan)

class fish(animal):
def __init__(self, length):
self.length = length
print "I'm a fish, weight %s, colour %s, length %s" % (self.weight,
self.colour, self.length)

Do you really want one animal instance to act both as bird and fish?
Wouldn't it be more sensible to instanciate either bird or fish (animal
being what is called an abstract class in other OOP languages)? bird and
fish would then have their own implementation of describeMyself() with
the 'print "I'm a..."' statement.

I must admit that I don't really understand what you are trying to
achieve...
 
M

MonkeeSage

Hi Lorcan,

Mabye thinking of it like this will help: birds and fishes (I love that
word, even if it is incorrect) can _do_ all the things that all animals
have in common: eat, drink, die, reproduce, &c; but that is generic.

class animal(object):
def eat(self, food): pass
...
class bird(animal): pass
class fish(animal): pass

If you want to talk about a specific bird or fish, then you have to say
more than just that it is an animal. Now, if all animals have a weight
and a color, but not all have the same weight or color, then you want
to say that this bird or fish is an animal which is colored X and
weighes Y.

class animal(object):
def __init__(self, weight, colour):
self.weight = weight
self.colour = colour
class bird(animal): pass # __init__ from animal is called implicitly
class fish(animal): pass

Now what if a bird and a fish have other attributes that not all
animals share (or at least specialized versions)? Well then you need to
say this bird is an animal which is colored X and weighs Y, but unlike
other animals, has a wingspan or length of Z.

class animal(object):
def __init__(self, weight, colour):
self.weight = weight
self.colour = colour
class bird(animal):
# override __init__ so we can say what _this_ animal is like
def __init__(self, weight, color, wingspan):
super(bird, self).__init__(weight, color)
self.wingspan = wingspan
class fish(animal):
def __init__(self, weight, color, length):
super(fish, self).__init__(weight, color)
self.length = length

Does this make more sense?

Regards,
Jordan
 
L

LorcanM

Thanks a lot folks for all the help. Its a lot clearer now.

If I could summarise my original misunderstanding about inheritance:

I belived that a sub class inherited a *specific instance* of the super
class.

This is clearly not right - the misunderstanding arose as I was
instantiating the super class from within the base class. As people
have pointed out it seems strange to instantiate an 'animal' and then
only later decide that it is a 'fish' or a 'bird'. Obviously my code is
an analogy to the problem I'm tackling. What I'm doing is a bit more
abstract: I'm instantiating a 'world' (as a super class) and then
various 'worldviews' as sub-classes. The 'worldviews' must know about
various aspects of the 'world' from which they are instantiated to be
able to do what they need to do (as the 'bird' needs to know about
'weight' and 'colour' to be able to describe itself).

Passing these aspects forward to the constructor of the sub class is
the solution I've implemented and it works and looks sensible.

Thanks again to all,


Lorcan.
 
B

bearophileHUGS

MonkeeSage:

If you have multiple inheritance do you need the old style init anyway?

class Animal1(object):
def __init__(self, weight, colour):
self.weight = weight
self.colour = colour

class Animal2(object):
def __init__(self, name):
self.name = name

class Bird(Animal1, Animal2):
def __init__(self, weight, color, wingspan, name):
super(Bird, self).__init__(weight, color) # Animal1
Animal2.__init__(self, name)
self.wingspan = wingspan
print self.weight, self.colour, self.wingspan, self.name

al = Bird(12, "White", 2, "Albatross")

Bye,
bearophile
 
M

MonkeeSage

If you have multiple inheritance do you need the old style init anyway?

I guess so, I'm not really sure. This page
<http://fuhm.net/super-harmful/> talks about super() and MRO and such,
but I have only glanced over it the other day. I will read it more
fully sometime. I tend not to use multiple inheritance very often, and
when I do I usually don't need to initialize the superclasses. So I've
never really thought about it or researched into it. Someone smarter
than me would probably know (hey wait a second -- you're smarter than
me! I've seen your code golf score, buddy! ;) ).

Regards,
Jordan
 
B

Bruno Desthuilliers

Gabriel Genellina wrote:
(snip)
When you construct an object instance, it is of a certain type from that
precise moment, and you can't change that afterwards.

Err... Actually, in Python, you can. It's even a no-brainer.

(snip)
 
B

Bruno Desthuilliers

LorcanM wrote:
(snip)
What I'm doing is a bit more
abstract: I'm instantiating a 'world' (as a super class) and then
various 'worldviews' as sub-classes. The 'worldviews' must know about
various aspects of the 'world' from which they are instantiated to be
able to do what they need to do

Mmmm... I suspect that you're falling into the good'ole trap of abusing
inheritance here. The fact that Worlview instances needs to know about a
World instance is usually modeled by composition, ie WorldViews are
instanciated with a world instance and keep a reference to it:

class World(object):
pass

class WorldView(object):
__metaclass__ = WorldViewMeta
def __init__(self, world, *args, **kw):
self.world = world

world = World()
wv = WorldView(world)


If you need/want to get WorldViews from the world itself, it's not much
more difficult:

class World(object):
def get_view(self, viewtype):
return viewtype(self)


world = World()
wv = world.get_view(WorldView)


And if you really need/want to be able to do the same thing but with the
WorldView name instead of the class itself:

class World(object):
_viewtypes = {}

@classmethod
def register_view_type(cls, viewtype):
cls._viewtypes[viewtype.__name__] = viewtype

def get_view(self, typename, *args, **kw):
if isinstance(typename, basestring):
return self._viewtypes[typename](self, *args, **kw)
else: # assume it's the class
return typename(self, *args, **kw)

def dothis(self):
return "dothis"

def dothat(self, bar):
return bar + bar

class WorldViewMeta(type):
def __init__(cls, classname, bases, dic):
World.register_view_type(cls)

class WorldView(object):
__metaclass__ = WorldViewMeta
def __init__(self, world, *args, **kw):
self.world = world

class SomeWorldView(WorldView):
def __init__(self, world, foo, parrot=False):
WorldView.__init__(self, world)
self.foo = foo
self.parrot = parrot

world = World()
some_view = world.get_view("SomeWorldView", 42, parrot=True)
# or
some_view = world.get_view(SomeWorldView, 42, parrot=True)


Also, if you want to be able to use the WorldViews like it was the world
itself, you can easily delegate:

class DelegateWorldView(WorldView):
def __init__(self, world):
WorldView.__init__(self, world)

# 'override' World.dothat:
def dothat(self, bar):
bar = bar * 3
return self.world.dothat(bar)

# automagically delegate other stuff:
def __getattr__(self, name):
return getattr(self.world, name)

HTH
 
W

Wildemar Wildenburger

Bruno said:
Err... Actually, in Python, you can. It's even a no-brainer.

Oh yeah, let's confuse the newbie, shall we :)

The art of teaching lies in what you *don't* tell the teachee in the
first run.
But factually, you're right. In the course of this OO lesson, however:
ssshhhhhhhh!

;)
wildemar
 
M

MonkeeSage

Ps. Aristotle can rest easy tonight:

class mortal(object): pass
class man(mortal): pass
Socrates = man()
all_men = mortal()
if Socrates == all_men:
print "Socrates == all_man"
else:
print "Undistributed Middle is indeed a fallacy"

;)

Regards,
Jordan
 
G

Gabriel Genellina

Err... Actually, in Python, you can. It's even a no-brainer.

Yes, but trying to explain that to a beginner would just make things
worse... You must grab the inheritance concept first.



Gabriel Genellina
Softlab SRL





__________________________________________________
Preguntá. Respondé. Descubrí.
Todo lo que querías saber, y lo que ni imaginabas,
está en Yahoo! Respuestas (Beta).
¡Probalo ya!
http://www.yahoo.com.ar/respuestas
 
L

LorcanM

Thanks Bruno,

That is a more natural way to do it. The code looks a lot cleaner now.


Lorcan.
 
B

Bruno Desthuilliers

Gabriel said:
Yes, but trying to explain that to a beginner would just make things
worse...

Agreed. But this newsgroup is not only read by beginners, and the last
part of your statement happens to be false. The first part is ok, and
would have been enough IMHO.
You must grab the inheritance concept first.

Mmm... It's clear that the OP didn't get the concept right...

OTHO, inheritance (not subtyping...) is a very overrated concept IMHO
and really not central to OO - at least with dynamically typed languages
(or using type inference). It's in fact nothing more than a special case
of composition/delegation. What's really important here is polymorphic
dispatch, which shouldn't (and, in Python, doesn't) rely on
implementation inheritance.

I really think that insisting on implementation inheritance is the wrong
way to teach OO. But I may not be a good teacher !-)
 

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

No members online now.

Forum statistics

Threads
473,764
Messages
2,569,564
Members
45,039
Latest member
CasimiraVa

Latest Threads

Top