Subclasses in Python

T

Thomas Philips

I'm teaching myself programming using Python, and have a question
about subclasses. My game has two classes, Player and Alien, with
identical functions, and I want to make Player a base class and Alien
a derived class. The two classes are described below

class Player(object):
#Class attributes for class Player
threshold = 50
n=0 #n is the number of players

#Private methods for class Player
def __init__(self,name):
self.name = name
self.strength = 100
Player.n +=1

def __del__(self):
Player.n -=1
print "You got me, Alien"

#Public methods for class Player
def blast(self,enemy,energy):
enemy.hit(energy)

def hit(self,energy):
self.strength -= energy
if(self.strength <= Player.threshold):
self.__del__()

class Alien(Player):
#Class attributes for class Alien
threshold = 100
n=0 #n is the number of players

#Private methods for class Alien
def __init__(self,name):
self.name = name
self.strength = 100
Alien.n +=1

def __del__(self):
Alien.n -=1
print "You got me, earthling"

#Public methods for class Alien
def hit(self,energy):
self.strength -= energy
if(self.strength <= Alien.threshold):
self.__del__()

The two classes are almost identical, except that:
1. When a new player is instantiated or destroyed, Player.n is
incremented/decremented, while when a new alien is instantiated,
Alien.n is incremented/decremented.
2. When hit by an energy blast, the player and the alien have
different thresholds below which they die.

How can I base the Alien's __init__(), __del__() and hit() methods on
the Player's methods, while ensuring that the appropriate class
variables are incremented/decremented when a new object is
instantiated and that the appropriate threshold is used when the
player/alien is hit by an energy bolt?

Thomas Philips
 
R

Roy Smith

I'm teaching myself programming using Python

I'm not sure how to parse that. Do you mean, "I'm teaching myself
programming, and I'm using Python", or do you mean, "I already know how
to program, and now I'm teaching myself Python"?
and have a question about subclasses. My game has two classes, Player
and Alien, with identical functions, and I want to make Player a base
class and Alien a derived class.
[...]
The two classes are almost identical, except that:
1. When a new player is instantiated or destroyed, Player.n is
incremented/decremented, while when a new alien is instantiated,
Alien.n is incremented/decremented.

It sounds from your description that you really want Player and Alien to
both be subclasses of a common base class. The reason I say that is
because Player.n doesn't get incremented when you create an Alien.
2. When hit by an energy blast, the player and the alien have
different thresholds below which they die.

Again, this sounds like two subclasses of a common base class; let's
call it Humanoid. It sounds like hit() and blast() belong in Humanoid,
and the "n" attribute should be a class variable of Alien and Player,
each of which have their own __init__().

It's not clear what to do with "self.strength = 100" which currently
you've got in each Player.__init__() and Alien.__init__(). One
possibility is that you could factor this out into Humanoid.__init__(),
and have each of the subclass's __init__() call Humanoid.__init__
(self). The other possibility is to just leave it in each subclass's
__init__() and not have a base class __init__() at all. The XP folks
would yell "refactor mercilessly", but in this case I'm not sure it's
justified.

BTW, there's nothing in the above that's specific to Python. The same
arguments would work in pretty much any OOPL.
 
S

Shalabh Chaturvedi

Thomas said:
I'm teaching myself programming using Python, and have a question
about subclasses. My game has two classes, Player and Alien, with
identical functions, and I want to make Player a base class and Alien
a derived class. The two classes are described below

<code defining classes Player and Alient snipped, but op's descrition
follows>
The two classes are almost identical, except that:
1. When a new player is instantiated or destroyed, Player.n is
incremented/decremented, while when a new alien is instantiated,
Alien.n is incremented/decremented.
2. When hit by an energy blast, the player and the alien have
different thresholds below which they die.

How can I base the Alien's __init__(), __del__() and hit() methods on
the Player's methods, while ensuring that the appropriate class
variables are incremented/decremented when a new object is
instantiated and that the appropriate threshold is used when the
player/alien is hit by an energy bolt?

Thomas Philips

One easy solution is to use self.__class__.n and self.__class__.threshold
instead of explicit Player.n and Player.threshold. Then derive Alien from
Player and only keep the two class attributes in it. Get rid of all methods
in Alien.

If you haven't already guessed how this works: when you call any method on
an Alient object, self.__class__ will be Alien, and if you call a method on
a Player object, self.__class__ will be Player.
 
T

Thomas Philips

I followed Shalabh's suggestion and rewrote Alien as a subclass of
Player, and used self.__Class__.<whatever I need to access> to access
the class attributes in the class and subclass. Works like a charm,
but I'm having some difficulty printing class names. I want
self.__class__ to return just the name of the class without some
ancillary stuff thrown in. A snippet of code follows:

class Player(object):
#Class attributes for class Player
threshold = 50
initial_strength=100
n=0

#Private methods for class Player
def __init__(self,name):
self.name = name
self.strength = self.__class__.initial_strength
self.__class__.n +=1
print self.__class__


class Alien(Player):
#Class attributes for subclass Alien
threshold = 30
initial_strength=150
n=0

When a new object is instantiated, the print statement in __init__
gives me
<class '__main__.Player'>
or
<class '__main__.Alien'>
How can I just get it to return

Player
or
Alien

Interestingly, if I do a class comparison of the form

if self.__class__== Alien:
foo
elif self.__class__== Player
bar

The comparison proceeds correctly. How can I get it to print the class
name cleanly? Do I have to convert <class '__main__.Alien'> to a
string and then use one or more string functions to clean it up?

Thomas Philips
 
P

Peter Otten

Thomas said:
I followed Shalabh's suggestion and rewrote Alien as a subclass of
Player, and used self.__Class__.<whatever I need to access> to access
the class attributes in the class and subclass. Works like a charm,
but I'm having some difficulty printing class names. I want
self.__class__ to return just the name of the class without some
ancillary stuff thrown in. A snippet of code follows:

class Player(object):
#Class attributes for class Player
threshold = 50
initial_strength=100
n=0

#Private methods for class Player
def __init__(self,name):
self.name = name
self.strength = self.__class__.initial_strength
self.__class__.n +=1
print self.__class__

make that
print self.__class__.__name__
class Alien(Player):
#Class attributes for subclass Alien
threshold = 30
initial_strength=150
n=0

When a new object is instantiated, the print statement in __init__
gives me
<class '__main__.Player'>
or
<class '__main__.Alien'>
How can I just get it to return

Player
or
Alien

Interestingly, if I do a class comparison of the form

if self.__class__== Alien:

This compares two *classes* not classnames. Even classes with the same name
defined, say, in a function would be recognized as not equal:
.... class A(object): pass
.... return A
....False

Now compare the names:
foo
elif self.__class__== Player
bar

The comparison proceeds correctly. How can I get it to print the class
name cleanly? Do I have to convert <class '__main__.Alien'> to a
string and then use one or more string functions to clean it up?

No, "<class '__main__.Alien'>" is the string that is generated when the
class Alien is converted to string. If you want something else you have to
change to a custom metaclass - better stick to Alien.__name__.

Peter
 
T

Terry Reedy

You have needed edit already. To explain a bit more ...
#Private methods for class Player
def __init__(self,name):
self.name = name
self.strength = self.__class__.initial_strength
self.__class__.n +=1
print self.__class__

print object # is same as
print str(object) # ie, prints stringifies everything
Interestingly, if I do a class comparison of the form

if self.__class__== Alien:
foo
elif self.__class__== Player
bar

The comparison proceeds correctly.

Here self.__class__ is left as the class object, as usual, and not
stringified.
How can I get it to print the class
name cleanly? Do I have to convert <class '__main__.Alien'> to a
string

That is what you did to print it '-)
and then use one or more string functions to clean it up?

Fortunately not.

Terry J. Reedy
 

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,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top