【问题标题】:property of class doesnt restrict the attribute类的属性不限制属性
【发布时间】:2016-03-31 09:44:16
【问题描述】:

所以我创建了一个类并希望该属性 hp 始终保持在 0 和 maxhp 之间 从理论上讲,使 hp 成为一个属性应该会给我希望的结果:但不知何故它不起作用。

有没有办法来回链接属性?所以我已经存储了单元类对象的位置。在 2 个地方,一个属性位置包含一个 [x,y] 数组,另一个时间它存储在 2 个属性 x 和 y 中,每个属性都包含一个 int。 更改 self.x 或 self.y 应该会更改 self.position ,反之亦然。

 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!

【问题讨论】:

  • 除了我的回答中给出的更改外,请考虑使用str.format() 来表示长__repr__。

标签: python class python-3.x attributes


【解决方案1】:

另一个问题是hp.setter。第二个if 语句应替换为elif,因为当hp 小于0 时,self.__hp 在第一个if 中设置为0,然后在没有elif 的情况下设置为负值在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

【讨论】:

  • 这不是真正的问题,除非maxhp 可以为负数。将其作为elif 更好/更清晰/优化,但这绝对不是问题。
  • 这是示例代码中的一个真正问题。当 hp
  • 好点,错过了。幸运的是,我在答案中输入的hp.setter 没有那个错误。我已经编辑了您的答案并添加了您的解释(并撤消了我的 -ve 投票)。 虽然设置依赖值不是 OP 的问题。
【解决方案2】:

在您的__init__ 中,self.hp = self.maxhp 应该是self.__hp = self.maxhp。这样它只能在 @property 方法中设置/获取。

您可以像处理hp 一样处理postion、x 和y。在内部使用_postion、_x和_y来对应getter和setter中的值;并在每个设置器中设置所有_prop 值。以position为例:

@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]

x 和 y 也是如此,不过我认为你应该只通过 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

顺便说一句,hp 设置器可以重写如下:

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

【讨论】:

  • 感谢您的帮助。 hp 的重写:我真的很喜欢它,因为实际上有很多属性需要类似的行为。
  • 是的,我使用类似的方法来实现这种行为。这也是 pythonic 的方式——几乎每个人都这样做。要添加的一件事,您是否一定需要 self.__hp 与 self._hp 的双下划线名称修饰,这只是被认为是私有的?仅当您不希望子类的实现干扰您的实现时,才真正需要这样做。
  • 这就是我在谷歌上搜索如何使用属性时显示的方式。所以没有没有任何区别。一个小问题“如果需要,在此之前进行检查”是什么意思?
  • “如果需要,在此之前检查”position,例如不允许负值(如果适用)或不允许超出地图范围的 x 和 y 值/网格。
猜你喜欢
  • 2020-03-17
  • 1970-01-01
  • 2011-02-22
  • 2016-04-16
  • 2012-05-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-10-16
相关资源
最近更新 更多