Reputation: 1167
I am looking for a way to alter an objects attribute depending upon a value parsed to a method. For example:
class Character(object):
def __init__(self, hp, mp, st, ag):
self.hp = hp
self.mp = mp
self.st = st
self.ag = ag
def increase_stat(self, stat, value):
''' Increase one of the attributes
(hp, mp, st, ag) by a given value.
'''
stat_dict = {'hp': self.hp,
'mp': self.mp,
'st': self.st,
'ag': self.ag}
stat_attr = stat_dict.get(stat)
# below should be equivalent to self.hp += value
stat_attr += value
hero = Character(hp=10, mp=4, st=3, ag=2)
hero.increase_stat(stat='hp', value=2)
# this should increase the hp by 2
print(hero.hp == 12)
I understand this doesn't work as stat_dict.get(stat) returns the value self.hp is pointing to rather than the actual self.hp object.
Instead of having the attributes as values for the dict, I have methods which increase each individual stat.
class Character(object):
def __init__(self, hp, mp, st, ag):
self.hp = hp
self.mp = mp
self.st = st
self.ag = ag
def increase_stat(self, stat, value):
''' Increase one of the attributes
(hp, mp, st, ag) by a given value.
'''
stat_method_dict = {'hp': self._increase_hp,
'mp': self._increase_mp,
'st': self._increase_st,
'ag': self._increase_ag}
alter_stat_method = stat_method_dict.get(stat)
alter_stat_method(value)
def _increase_hp(self, value):
self.hp += value
def _increase_mp(self, value):
self.mp += value
def _increase_st(self, value):
self.st += value
def _increase_ag(self, value):
self.ag = value
hero = Character(hp=10, mp=4, st=3, ag=2)
hero.increase_stat(stat='hp', value=2)
# this should increase the hp by 2
print(hero.hp == 12)
My problem with this is it is repetitive and if I decide to add more attributes/stats to the class then this will only increase the number of repetitive methods. I was wondering if there is a better solution to this than what I have produced above?
Seems very obvious now. Thanks all.
class Character(object):
def __init__(self, hp, mp, st, ag):
self.hp = hp
self.mp = mp
self.st = st
self.ag = ag
def increase_stat(self, stat, value):
''' Increase one of the attributes
(hp, mp, st, ag) by a given value.
'''
current = getattr(self, stat)
setattr(self, stat, current+value)
Upvotes: 1
Views: 373
Reputation: 96287
Your stat-dict really serves no purpose. Use getattr
and setattr
to dynamically manipulate attributes. So, something like:
def increase_stat(self, stat, value):
setattr(self, stat, value + getattr(self, stat))
So, e.g.:
In [30]: class Dummy:
...: def __init__(self):
...: self.intelligence = 0
...: self.strength = 10
...: self.hp = 100
...: def increase_stat(self, stat, value):
...: setattr(self, stat, value + getattr(self, stat))
...:
In [31]: d = Dummy()
In [32]: d.strength
Out[32]: 10
In [33]: d.increase_stat('strength', 10)
In [34]: d.strength
Out[34]: 20
Perhaps easier to read:
def increase_stat(self, stat, value):
current = getattr(self, stat)
setattr(self, stat, current + value)
Note, this is better than manipulating the instance __dict__
directly, which will break with descriptors like property
objects. Not to mention objects that don't have a __dict__
e.g. types with __slots__
Upvotes: 2
Reputation: 71471
You can use the __setitem__
method for a more concise solution:
class Character(object):
def __init__(self, *args):
self.__dict__ = dict(zip(['hp', 'mp', 'st', 'ag'], args))
def __setitem__(self, name, val):
self.__dict__[name] += val
hero = Character(10, 4, 3, 2)
hero['hp'] = 2
print(hero.hp)
Output:
12
However, this strategy can also be implemented using a custom method:
class Character(object):
def __init__(self, *args):
self.__dict__ = dict(zip(['hp', 'mp', 'st', 'ag'], args))
def increase_stat(self, stat, value):
self.__dict__[stat] += value
hero = Character(10, 4, 3, 2)
hero.increase_stat(stat='hp', value=2)
Output:
12
Upvotes: 0