Ryanless
Ryanless

Reputation: 144

property of class doesnt restrict the attribute

So i made a class and want, that attribute hp stays always between 0 and maxhp In theory making hp a property should give me the wished result: Somehow it doesnt work though.

Is there way to link attributes for and back? So i have stored the position of the unit class object. At 2 places, once the attribute position which contains a [x,y] array and the other time its stored in 2 attributes x and y and each contains a int. Changing self.x or self.y should changes self.position and the other way around too.

 class units(object):

    def __init__(self,typus, position, stats):
        self.type = typus

        #they should be linked both directions
        self.position = position
        self.x = self.position[0]
        self.y = self.position[1]

        self.attack = stats[0]
        self.defense = stats[1]
        self.maxhp = stats[2]
        self.hp = self.maxhp

    def __repr__(self):
        text = "This a %s at position [%s,%s].\n  Attack: %s \n Defense: %s \n Hp : %s/%s \n "  \
               % (self.type,self.position[0],self.position[1],  self.attack, self.defense, self.hp, self.maxhp)
        return text


    # hp set to always be in between 0 and maxhp
    @property
    def hp(self):
        return self.__hp

    @hp.setter
    def hp(self, hp):
        if hp < 0:
            self.__hp = 0
        if hp > self.maxhp:
            self.__hp = self.maxhp
        else:
            self.__hp = hp

    def takedmg(self,dmg):
        self.hp -= max(dmg-self.defense, 0)
        if self.hp <= 0:
            self.alive = False
        return self.hp



p = units("peasant", [1,1],  [2,0,30])
p.takedmg(100)
print (p.hp)     # it should be 0!

Upvotes: 0

Views: 98

Answers (2)

apr
apr

Reputation: 390

Another problem is in hp.setter. The second if statement should be replaced with elif because when hp is less than 0, self.__hp is set to 0 in first if and then, without elif, it is set to a negative value in else:

@hp.setter
def hp(self, hp):
    if hp < 0:
        self.__hp = 0
    elif hp > self.maxhp:
        self.__hp = self.maxhp
    else:
        self.__hp = hp

Upvotes: 1

aneroid
aneroid

Reputation: 15987

In your __init__, the line self.hp = self.maxhp should be self.__hp = self.maxhp. That way it's only set/get in the @property methods.

You would handle postion, x and y the same way as you've done for hp. Use _postion, _x and _y internally to correspond to the values in the getters and setters; and set all of the _prop values in the setters of each. Using position as a an example:

@property
def position(self):
    return self._position

@position.setter
def position(self, position):
    self._position = position  # do checking before this if needed
    self._x = position[0]
    self._y = position[1]

Similarly for x and y, though I think you should only do it via position:

@property
def x(self):
    return self._x

@x.setter
def x(self, x):
    self._x = x
    # self._y remains unchanged
    self._position[0] = x

Btw, the hp setter can be re-written as follows:

@hp.setter
def hp(self, hp):
    self.__hp = max(0, min(hp, self.maxhp))

Upvotes: 0

Related Questions