如果我的理解是正确的,那么属性用于getter和setter。用@property
修饰getter或setter可以让我们修改、使用它等,就好像它是一个属性一样,所以与其做MyClass.foo()
之类的事情,不如做MyClass.foo
。我读到这样做是为了让代码更加干净并提高可读性。使用@property
装饰getter和setter还有其他原因吗?我在某个地方读到,当想要进行更改时,最好使用属性来避免破坏代码,我不明白为什么当你有不是属性的getter和setter方法时,你会需要属性。
正如您在评论中链接的文章所说:
Python属性的主要优点是,它们允许您将属性作为公共API的一部分公开。如果你需要更改底层实现,然后可以打开属性在任何时候进入一处房产都不会有太多痛苦。
这里的关键字是";暴露你的属性";。
假设您有一个具有实例属性weight
的类Object
,您最初将其作为API的一部分公开,并允许最终用户自由修改:
class Object:
def __init__(self):
self.weight = 0
但您后来发现,一些最终用户正在用负值设置weight
,这应该被视为无效:
o = Object()
o.weight = -1
因此,您可以通过添加getter和setter方法来修改类,并使用_
前缀重命名原始属性以隐藏它:
class Object:
def __init__(self):
self._weight = 0
def get_weight(self):
return self._weight
def set_weight(self, value):
assert value >= 0 # validate that weight is not negative
self._weight = value
但是,您需要对您公开的API进行更改,并告诉最终用户在他们的终端上进行相应的更改:
o = Object()
o.set_weight(-1) # now this will be properly disallowed and raise an exception
这对您(必须更改公开的API文档(和最终用户(必须更改他们使用API的方式(来说都很麻烦。
现在,通过将weight
属性转换为属性:
class Object:
def __init__(self):
self._weight = 0
@property
def weight(self):
return self._weight
@weight.setter
def weight(self, value):
assert value >= 0 # validate that weight is not negative
self._weight = value
最终用户可以继续使用他们现有的代码:
o = Object()
o.weight = -1 # raises an exception
他们现在可以获得对weight
进行适当验证的好处,而不需要知道底层实现已经从属性变为setter方法。
没错,@property
类似于getter/setter,但在调用时表现略有不同。
当使用普通的getter/setter时,例如:
class Foo:
def getFoo():
# ...
def setFoo(foo):
# ...
my_foo = Foo()
# print foo value
print(my_foo.getFoo())
# set foo to 100
my_foo.setFoo(100)
正如你所看到的,这有点难看。所以Python有@property
装饰器来解决这个问题:
class Foo:
def __init__(self):
self.inner_foo = 1
@property
def foo(self):
return self.inner_foo
@foo.setter
def foo(self, value):
self.inner_foo = value
foo = Foo()
print(foo.foo)
foo.foo = 100
print(foo.foo)
现在,foo
属性在使用时就像一个普通属性一样,使您的代码更加简洁。