Subclasses in Python

Discussion in 'Python' started by Thomas Philips, Apr 23, 2004.

  1. 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
    Thomas Philips, Apr 23, 2004
    #1
    1. Advertising

  2. Thomas Philips

    Roy Smith Guest

    (Thomas Philips) wrote:
    > 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.
    Roy Smith, Apr 23, 2004
    #2
    1. Advertising

  3. Thomas Philips wrote:

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

    --
    Shalabh
    Shalabh Chaturvedi, Apr 23, 2004
    #3
  4. 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
    Thomas Philips, Apr 29, 2004
    #4
  5. Thomas Philips

    Peter Otten Guest

    Thomas Philips wrote:

    > 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:

    >>> def makeClass():

    .... class A(object): pass
    .... return A
    ....
    >>> A1 = makeClass()
    >>> A2 = makeClass()
    >>> A1

    <class '__main__.A'>
    >>> A2

    <class '__main__.A'>
    >>> A1 == A2

    False

    Now compare the names:

    >>> A1.__name__, A2.__name__

    ('A', 'A')
    >>> A1.__name__ == A2.__name__

    True
    >>>


    > 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
    Peter Otten, Apr 29, 2004
    #5
  6. Thomas Philips

    Terry Reedy Guest

    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
    Terry Reedy, Apr 29, 2004
    #6
    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. Bura Tino

    Subclasses in interfaces

    Bura Tino, Nov 3, 2003, in forum: Java
    Replies:
    17
    Views:
    556
    Thomas G. Marshall
    Nov 7, 2003
  2. Praveen
    Replies:
    1
    Views:
    368
    Woebegone
    Nov 21, 2003
  3. Marc Twain
    Replies:
    2
    Views:
    664
    Chris Uppal
    Jan 7, 2004
  4. Steve Nakhla
    Replies:
    0
    Views:
    614
    Steve Nakhla
    Sep 27, 2004
  5. Robert Brewer

    RE: Subclasses in Python

    Robert Brewer, Apr 29, 2004, in forum: Python
    Replies:
    3
    Views:
    291
    Terry Reedy
    Apr 30, 2004
Loading...

Share This Page