我制作了这个简单的程序:
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__
方法,我可以在稍后在游戏中使用之前加载我的类?
答案 0 :(得分:3)
您获得如此奇怪的输出的原因是因为_health
是您班级中的方法,而health
(没有_
)是保存该值的变量。你正在打印_health
,打印方法看起来很奇怪。您可能打算改为打印health
。
但是,您不应该首先创建这样的setter和getter方法,而是按原样使用属性。应在__init__
方法中设置所有属性,该方法在创建对象时调用。这样可以确保对象在创建后始终具有所有属性(您可以将任何属性的值初始化为None
)。
以下是我执行程序的示例:
class Enemy:
def __init__(self, name, health):
self.name = name
self.health = health
现在,您可以轻松访问敌人的name
和health
属性,而无需任何额外的麻烦:
>>> 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>>