在更新值时, init 方法仍然使用旧的属性值。
class Email:
def __init__(self, name):
self.name = name
self.email = self.name + "@hotmail.com"
def details(self):
return f'{self.name} | {self.email}'
person = Email("James")
print(person.details())
person.name = "Michael"
print(person.details())
得到的输出:
James | James@hotmail.com
Michael | James@hotmail.com
预期输出:
James | James@hotmail.com
Michael | Michael@hotmail.com
我在做什么错了?
谢谢
答案 0 :(得分:4)
如果我们在用行person
实例化person = Email("James")
对象之后立即打开它,则将是这样的:
person {
"name" : "James",
"email" : "James@hotmail.com"
}
如果像您使用name
一样更新此person
对象中的person.name = "Michael"
变量,然后再次打开person
对象,则为:
person {
"name" : "Michael",
"email" : "James@hotmail.com"
}
请注意,在此阶段,它仍然是我们先前实例化的同一person
对象,并且email
变量没有从其先前状态更改,因为我们对此没有做任何事情,但是。
email
字段设置为property
,并使用name
变量将其动态设置,The answer posted by @chepner非常好而且干净。以下是@chepner的代码的副本:
class Email:
def __init__(self, name):
self.name = name
# self.email = self.name + "@hotmail.com"
@property
def email(self):
return f'{self.name}@hotmail.com'
def details(self):
return f'{self.name} | {self.email}'
property
是什么,如何使用? property
是Python Built-in Function,property
对象具有以下方法:
getter
:用于获取属性值setter
:用于设置属性值deleter
:用于删除属性值现在,@chepner 's answer中到底发生了什么?在下面的几行中,我们将email
设置为property
:
@property
def email(self):
return f'{self.name}@hotmail.com'
此修饰功能也可以用作getter
,例如person.email
。
请注意,在这里我们没有将其链接到变量(如Python documentation example所示),如果需要/需要,我们可以通过替换return
语句并设置一个_email
中的__init__
变量:
def __init__(self, input_name):
self._name = input_name
self._email = f'{self._name}@hotmail.com'
@property
def email(self):
return self._email
然后,对于setter
和deleter
,我们可以将它们创建为:
@email.setter
def email(self, input_email):
self._email = input_email
@email.deleter
def email(self):
del self._email
请注意,getter
,setter
和deleter
方法的名称与property
相同,只是装饰器不同。
从问题描述中并不需要支持单独更新电子邮件地址,而是仅在此示例之后,如果我们运行person.email = "Michael@hotmail.com"
,因为email
是property
,因此它正在触发setter
将值设置为_email
变量。
返回@chepner 's answer中的details
方法:
def details(self):
return f'{self.name} | {self.email}'
通过执行self.email
,我们触发getter
返回电子邮件地址,该电子邮件地址是在return
语句return f'{self.name}@hotmail.com'
中动态生成的。
答案 1 :(得分:2)
在此示例中,在类的self.email
方法中分配了__init__
,该方法仅在创建Email
的实例时调用。这样,当重新分配self.name
时,self.email
不会更改。要解决此问题,您可以使用property
装饰器:
class Email:
def __init__(self, name):
self._name = name
self._email = f'{name}@hotmail.com'
def details(self):
return f'{self._name} | {self._email}'
@property
def name(self):
return self._name
@name.setter
def name(self, _new_name):
self._name = _new_name
self._email = f'{_new_name}@hotmail.com'
person = Email("James")
print(person.details())
person.name = "Michael"
print(person.details())
输出:
James | James@hotmail.com
Michael | Michael@hotmail.com
答案 2 :(得分:1)
正如@ Ajax1234所说,创建新实例时将调用init函数。如果您熟悉面向对象的语言,就可以将其视为构造函数。
因此,如果仅更改person.name,则可以更改名称字段,但不能更改分配了较旧名称名称的电子邮件变量。
关于这种情况,您有几种选择:
您可以创建一个名为Michael的新电子邮件对象。
您可以像在init函数中一样直接重新分配电子邮件。
您可以为setName(name)
之类的名称创建一个“ setter”方法,并且可以在此功能中更新电子邮件。因此,当您呼叫设置器时,它会自动更新电子邮件。
答案 3 :(得分:1)
最简单的解决方法是将email
设置为属性,而不是您在__init__
中设置的属性。
class Email:
def __init__(self, name):
self.name = name
# self.email = self.name + "@hotmail.com"
@property
def email(self):
return f'{self.name}@hotmail.com'
def details(self):
return f'{self.name} | {self.email}'