assigning values in __init__
Nick Craig-Wood
nick at craig-wood.com
Tue Nov 7 04:30:05 EST 2006
Larry Bates <larry.bates at websafe.com> wrote:
> John Salerno wrote:
> > Let's say I'm making a game and I have this base class:
> >
> > class Character(object):
> >
> > def __init__(self, name, stats):
> > self.name = name
> > self.strength = stats[0]
> > self.dexterity = stats[1]
> > self.intelligence = stats[2]
> > self.luck = stats[3]
> >
> > Is this a good way to assign the values to the different attributes?
> > Should 'stats' be a list/tuple (like this), or should I do *stats instead?
> >
> > I'm trying to think ahead to when I might want to add new attributes,
> > and I want to make sure this doesn't get crazy with individual
> > parameters instead of just the one list.
> >
> > Or maybe there's some way to loop through two lists (the stats and the
> > attributes) and assign them that way? I was thinking of a nested for
> > statement but that didn't seem to work.
>
> Sounds like what you should be doing is something like keyword arguments
> instead.
>
> class Character(object):
> def __init__(self, name, **kwargs):
> self.name=name
> for key, value in kwargs.items():
> setattr(self, key, value)
>
>
> z=Character('name', strength=10, dexterity=5, intelligence=3,
> luck=0)
I would say this is a bad idea because you'll get no error messages if
you mis-spell 'dexterity' for instance.
I'd prefer to see a bit more error checking, something like
class Character(object):
attributes = set(['strength', 'dexterity', 'intelligence', 'luck'])
def __init__(self, name, **kwargs):
self.name=name
for key, value in kwargs.items():
if key not in self.attributes:
raise AttributeError("Bad attribute %s for %s" % (key, self.__class__.__name__))
setattr(self, key, value)
z = Character('name', strength=10, dexterity=5, intelligence=3, luck=0)
>>> Character('name', strength=10, dexterity=5, intelligence=3, luck=0)
<Character object at 0xb7dac72c>
>>> Character('name', strength=10, dextrity=5, intelligence=3, luck=0)
Traceback (most recent call last):
File "<stdin>", line 1, in ?
File "z.py", line 7, in __init__
raise AttributeError("Bad attribute %s for %s" % (key, self.__class__.__name__))
AttributeError: Bad attribute dextrity for Character
>>>
You can then add to attributes in the subclasses
class MagicCharacter(Character):
attributes = Character.attributes | set(['spells', 'wand'])
>>> MagicCharacter('name', strength=10, dexterity=5, intelligence=3, luck=0, spells=1)
<MagicCharacter object at 0xb7ce86ac>
>>>
If I was writing this, I'd probably just stick to named parameters
unless I had more than 10 parameters. Named parameters are easy to
manage, and you never get confused by their position.
Also pychecker understands named parameters where as if you use a
scheme like the above you'll cause pychecker problems!
--
Nick Craig-Wood <nick at craig-wood.com> -- http://www.craig-wood.com/nick
More information about the Python-list
mailing list