这是 Python Class 可变的吗?
Is this Python Class mutable?
这个对象是可变的吗?
class Clock(object):
def __init__(self, time):
self.time = time
def print_time(self):
print(self.time)
boston_clock = Clock('5:30')
paris_clock = boston_clock
paris_clock.time = '10:30'
boston_clock.print_time()
即使我期望打印“5:30”,它也会打印“10:30”,因为字符串是不可变的。对比代码:
a = "Hello"
b = a
b += " World"
print(a)
它打印 "Hello"。
对象 Clock 表现为一个列表,所以我认为它是可变的,但我不知道为什么。在那种情况下,我怎样才能使时钟 class 不可变?
字符串确实是 immutable,但是,在您的示例中,您更改的不是字符串变量,而是对象的属性。该属性引用一个值,因此通过重新分配它,您只需使其指向另一个值。
Python 是一种非常动态的语言,很难使某些东西真正免受突然突变的影响。但是,有一个约定,在属性名称的开头使用 _
,表示不应访问 and/or 由 class 之外的任何代码修改。如果你仍然想要 public time
属性,你可以将其设为 属性:
class Clock:
def __init__(self, time):
self._time = time
@property
def time(self):
return self._time
def print_time(self):
print(self._time)
UPD: 顺便说一句,在 Python 中,变量与属性没有太大区别。要访问 my_clock.time
,解释器需要在对应于 my_time
目的。同时,当您访问局部变量 a
时,在与当前局部范围相对应的另一个符号 table (又名字典)中正在执行类似的查找。试试这个片段:
a = "Hello"
b = a
b += " World"
print(a)
locals()['a'] = "foobar"
print(a)
即使字符串是 immutable,第二个打印输出 foobar
.
如果你真的想强制执行你预期的行为,你可以使用 getter/setter 模式:
class Clock(object):
def __init__(self, time):
self._time = time
@property
def time(self):
print(self._time)
@time.setter
def time(self, value):
raise AttributeError("Clock time does not support re-assignment")
用法:
>>> c = Clock("5:30")
>>> c.time
5:30
>>> c.time = "10:30"
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 9, in time
AttributeError: Clock time does not support re-assignment
您也可以只 pass
而不是引发异常,但是当他们以其他方式期望更改属性时,这可能会以代码 "failing silently" 的形式出现。
那是说:对于@IvanVelichko 的回答,如果用户想要不厌其烦地这样做,底层 _time
属性仍然可以重新分配给:
>>> c._time = "10:30"
>>> c.time
10:30
更广泛地说,由于上述原因,getter/setter 模式在 Python 中的使用频率远低于 Java。
这个对象是可变的吗?
class Clock(object):
def __init__(self, time):
self.time = time
def print_time(self):
print(self.time)
boston_clock = Clock('5:30')
paris_clock = boston_clock
paris_clock.time = '10:30'
boston_clock.print_time()
即使我期望打印“5:30”,它也会打印“10:30”,因为字符串是不可变的。对比代码:
a = "Hello"
b = a
b += " World"
print(a)
它打印 "Hello"。 对象 Clock 表现为一个列表,所以我认为它是可变的,但我不知道为什么。在那种情况下,我怎样才能使时钟 class 不可变?
字符串确实是 immutable,但是,在您的示例中,您更改的不是字符串变量,而是对象的属性。该属性引用一个值,因此通过重新分配它,您只需使其指向另一个值。
Python 是一种非常动态的语言,很难使某些东西真正免受突然突变的影响。但是,有一个约定,在属性名称的开头使用 _
,表示不应访问 and/or 由 class 之外的任何代码修改。如果你仍然想要 public time
属性,你可以将其设为 属性:
class Clock:
def __init__(self, time):
self._time = time
@property
def time(self):
return self._time
def print_time(self):
print(self._time)
UPD: 顺便说一句,在 Python 中,变量与属性没有太大区别。要访问 my_clock.time
,解释器需要在对应于 my_time
目的。同时,当您访问局部变量 a
时,在与当前局部范围相对应的另一个符号 table (又名字典)中正在执行类似的查找。试试这个片段:
a = "Hello"
b = a
b += " World"
print(a)
locals()['a'] = "foobar"
print(a)
即使字符串是 immutable,第二个打印输出 foobar
.
如果你真的想强制执行你预期的行为,你可以使用 getter/setter 模式:
class Clock(object):
def __init__(self, time):
self._time = time
@property
def time(self):
print(self._time)
@time.setter
def time(self, value):
raise AttributeError("Clock time does not support re-assignment")
用法:
>>> c = Clock("5:30")
>>> c.time
5:30
>>> c.time = "10:30"
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 9, in time
AttributeError: Clock time does not support re-assignment
您也可以只 pass
而不是引发异常,但是当他们以其他方式期望更改属性时,这可能会以代码 "failing silently" 的形式出现。
那是说:对于@IvanVelichko 的回答,如果用户想要不厌其烦地这样做,底层 _time
属性仍然可以重新分配给:
>>> c._time = "10:30"
>>> c.time
10:30
更广泛地说,由于上述原因,getter/setter 模式在 Python 中的使用频率远低于 Java。