使用方法设置类的变量

时间:2017-06-19 07:48:25

标签: python python-3.x

我制作了这个简单的程序:

class Enemy(object):
    def set_name(self, name):
        self.name = name
        return name

    def set_health(self, health):
        self.health = health
        return health

Orc = Enemy()
Orc.set_name('Orc')
Orc.set_health(76)

我理解这是有效的,但我想知道这与使用__init__之间的区别是什么?例如,我做了类似的程序:

class Enemy(object):
    def __init__(self, name):
        self.name = name

    def name(self):
        return self.name

    def _health(self, health):
        self.health = health
        return self.health

Orc = Enemy('Orc')
Orc._health(85)
print(Orc._health)
print(Orc.name)

但我在输出中得到了这个:

<bound method Enemy._health of <__main__.Enemy object at 0x00ED1670>>
Orc

我想说的是这种__init__方法做了一些重要的事情,例如我正在制作游戏时?也许如果我使用__init__方法,我可以在稍后在游戏中使用之前加载我的类?

2 个答案:

答案 0 :(得分:3)

您获得如此奇怪的输出的原因是因为_health是您班级中的方法,而health(没有_)是保存该值的变量。你正在打印_health,打印方法看起来很奇怪。您可能打算改为打印health

但是,您不应该首先创建这样的setter和getter方法,而是按原样使用属性。应在__init__方法中设置所有属性,该方法在创建对象时调用。这样可以确保对象在创建后始终具有所有属性(您可以将任何属性的值初始化为None)。

以下是我执行程序的示例:

class Enemy:
    def __init__(self, name, health):
        self.name = name
        self.health = health

现在,您可以轻松访问敌人的namehealth属性,而无需任何额外的麻烦:

>>> orc = Enemy('My Orc', 100)
>>> print(orc.name)
'My Orc'
>>> orc.health -= 30  # Deal 30 damage
>>> print(orc.health)
70

如果你需要隐藏这些东西,例如让name“私有”以便在创建对象后无法更改它,你可以使用前导下划线将这些属性标记为“私有” :

class Enemy:
    def __init__(self, name, health):
        self._name = name  # "private" variable which can't be changed
        self.health = health

这不会使它真正私密,您仍然可以通过orc._name访问它,但是一个主要的下划线表示其他人不应该自己更改这些变量,这可能会导致问题。任何带有前导下划线的东西都不应该在课堂外触及。

但另一个问题出现了。如果我们不允许在课堂外触摸_name,我们如何打印出该名称?这是您创建一个类似于之前的功能的地方:

class Enemy:
    def __init__(self, name, health):
        self._name = name
        self.health = health

    def get_name(self):
        return self._name

现在,您可以使用此方法轻松获取名称:

>>> orc = Enemy('test', 0)
>>> print(orc.get_name())
test

但是还有更好的方法。看看有时你需要写orc.health,有时候orc.get_name()是多么丑陋和不一致?这就是Python具有内置property功能的原因!这允许您为这些属性创建getter / setter方法,同时保留属性的语法!让我们看看它如何适用于getter:

class Enemy:
    def __init__(self, name, health):
        self._name = name
        self.health = health

    @property
    def name(self):
        return self._name

现在,当我们访问orc.name时,由于它被标记为属性,它将立即自动调用,而不需要括号:

>>> orc = Enemy('orcy', 12)
>>> orc.name  # calls the name() function automatically
'orcy'

我们甚至可以创建自定义setter函数,这样当你orc.name = 5时,它会秘密调用orc.name.setter(5)

class Enemy:
    def __init__(self, name, health):
        self._name = name
        self.health = health

    @property
    def name(self):
        return self._name

    @name.setter
    def name(self, value):
        if not isinstance(value, string):  # Don't allow numbers, lists, etc.
            raise ValueError('Invalid name!')
        self._name = value

现在您可以像这样使用它:

>>> orc = Enemy('Test', 1)
>>> orc.name
'Test'
>>> orc.name = 'Hmm'
>>> orc.name
'Hmm'
>>> orc.name = []
ValueError: Invalid name!
>>> orc.name
'Hmm'
>>> orc.name = 123
ValueError: Invalid name!

答案 1 :(得分:-1)

你有2个选项,使用构造函数(你在创建对象时给出值health和name)或者你使用setter(这意味着name和health可以在创建对象后改变它的值。 。 现在,这个:

print(Orc._health)

正在打印方法而不是类

的字段/成员

这就是你得到<bound method Enemy._health of <__main__.Enemy object at 0x00ED1670>>

的原因