所以我正在重构我的代码,使其更加Python化——特别是我已经学会了使用显式getter和setter应该用@property代替。我的情况是,我有一个具有初始化bar
属性的Example
类(初始化帮助我知道用户设置了bar
(:
class Example:
def __init__(self):
self.bar = 'initializedValue'
@property
def bar(self):
return self._bar
@bar.setter
def bar(self, b):
self._bar = b
def doIfBarWasSet():
if self.bar != 'initializedValue':
pass
else:
pass
在运行foo = Example()
之后,我的调试器显示foo有两个属性:_bar
和bar
,都设置为'initializedValue'
。此外,当我运行foo.bar = 'changedValue'
或foo._bar = 'changedValue'
时,它们都会更改为'changedValue'
。为什么有两个属性?这不是多余的吗?我想我理解为什么会有_bar
属性——我在@bar.setter
中添加了它,但为什么会有作为字符串属性的bar
?bar
不应该是一种导致bar
@property
的方法吗?
很好。请记住,bar
不是实例属性,而是类的属性。由于它的类型为property
,因此它实现描述符协议,以便从实例访问时其行为不同。如果e
是Example
的实例,则e.bar
不会为您提供分配给Example.bar
的property
的实例;它给出了Example.bar.__get__(e, Example)
的结果(在本例中,它恰好是Example.bar.fget(e)
,其中fget
是由@property
修饰的原始函数(。
简而言之,每个实例都有自己的_bar
属性,但对该属性的访问是由类属性Example.bar
介导的。
如果您编写这个最小(并且足够,因为在这种情况下getter和setter都不需要def
语句(定义,则更容易看出bar
是一个类属性。
class Example:
def __init__(self):
self.bar = "initalizedValue"
bar = property(lambda self: self._bar, lambda self, b: setattr(self, '_bar', b))
或者更一般地
def bar_getter(self):
return self._bar
def bar_setter(self, b):
self._bar = b
class Example:
def __init__(self):
self.bar = "initalizedValue"
bar = property(bar_getter, bar_setter)