On Mon, 06 Nov 2006 16:57:58 -0500, 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?
Whenever possible, think about writing self-documenting code: def __init__(self, name, strength, dexterity, intelligence, luck): self.name = name self.strength = strength # etc. seems perfectly acceptable to me (if a tad verbose, but that isn't a big deal -- write once, never touch again). The problem with function signatures like these: def __init__(self, name, stats): def __init__(self, name, *stats): is that the format of stats is left unstated. Is it (luck, strength, intelligence) or (strength, intelligence, luck) or (wisdom, charisma, power, health) or something else? You shouldn't need to read the code line by line to find out, and relying on documentation risks having the code and docs get out of sync. If you expect the stats to be passed as a single tuple, you can still make it explicit: just wrap the field names within brackets. def __init__(self, name, (strength, dexterity, intelligence, luck) ): > I'm trying to think ahead to when I might want to add new attributes, If this is likely, you could do something like this: def __init__(self, name, **stats): self.name = name self.__dict__.update(stats) Adding extra attributes is fine, since they will just be ignored, but what if the caller adds an attribute "itnelligence" (instead of intelligence)? You're now writing lots of code like this: def save_intelligence(self, threshold): """Roll a saving throw against intelligence""" try: return roll(self.intelligence) > threshold except AttributeError: # character has no intelligence, so always fails return False Yes, you can make that easier with currying, decorators etc. but why not make sure your characters have the required attributes in the first place? One way of doing that would be to add default values for the required attributes in the class, and let instances inherit those defaults from the class. > and I want to make sure this doesn't get crazy with individual > parameters instead of just the one list. If you've got that many character attributes, I'm guessing that your game will be a tad hard to play :-) If you have more than a half-dozen or ten character attributes, you could consider encapsulating them in some way. E.g. group-related attributes and pass them as tuples: power => (constitution, health, anaerobic_strength, aerobic_strength) intelligence => (IQ, wisdom, dexterity, book_learning, street_wisdom) charisma => (beauty, chutzpah, attractiveness, persuasiveness) senses => (vision, hearing, smell, telepathy, empathy, feeling, spacial) others => (luck, determination, laziness, attention_to_detail) You could then roll against power, say, by giving a set of weights: character.roll('power', (0.0, 0.0, 0.9, 0.1)) gives anaerobic strength a weighting of 90% and aerobic 10%. But again, I think that if your roll-playing game needs to have such fine-grained attributes, I think it will be too complex to be fun. > 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. def __init__(self, stats): names = ['strength', 'dexterity', 'intelligence', 'luck'] for name, stat in zip(names, stats): setattr(self, name, stat) -- Steven. -- http://mail.python.org/mailman/listinfo/python-list