alt*_*-f4 5 python getter setter properties python-3.x
我无法理解为什么 getter/setter 方法的名称必须与属性具有相同的名称。
我尝试在这里阅读亚伦·霍尔的答案,但我仍然找不到(或错过了)关于为什么我们必须使用各自名称的解释。
class Car(object):
def __init__(self, color='blue'):
self.color = color
self.current_model = 'Opel'
@property
def model(self, new_model):
return self.current_model
@model.setter
def model(self, new_model):
if new_model == 'Audi':
raise ValueError ('NO AUDI ALLOWED')
else:
self.current_model = new_model
# model = model.setter(models) but doing this works
@model.getter
def model(self):
return self.current_model
Run Code Online (Sandbox Code Playgroud)
编辑: 我发现令人困惑的是,如果我将方法重命名为:
@model.setter
def model_new(self, new_model):
if new_model == 'Audi':
raise ValueError ('NO AUDI ALLOWED')
else:
self.current_model = new_model
Run Code Online (Sandbox Code Playgroud)
我尝试运行:
audi = Car()
audi.model = 'BMW' # will get AttributeError: can't set attribute
Run Code Online (Sandbox Code Playgroud)
我预计这不起作用,因为 getter、setter 和 deleter 方法创建属性的副本,并且更改方法的名称就像修改不同属性的属性一样。这就像做:models = model.setter(models)。
但我不确定我是否正确理解了这一点
函数名称需要相同,因为@model.setter不会更新现有属性;它会将其替换为基于现有属性的新属性。当您使用属性方法作为装饰器时,属性的名称是最后装饰的函数的名称。
记住,
@model.setter
def model(self, new_model):
if new_model == 'Audi':
raise ValueError ('NO AUDI ALLOWED')
else:
self.current_model = new_model
Run Code Online (Sandbox Code Playgroud)
大致相当于
def tmp(self, new_model):
if new_model == 'Audi':
raise ValueError ('NO AUDI ALLOWED')
else:
self.current_model = new_model
model = model.setter(tmp)
Run Code Online (Sandbox Code Playgroud)
也就是说,def语句( model) 所绑定的名称与replace 的结果绑定model.setter。如果您使用不同的名称,那么您就更改了该属性的名称。
最直接的方法是同时提供 getter(以及可选的 setter 和 deleter):
def foo_get(self):
...
def foo_set(self, v):
...
foo = property(foo_get, foo_set)
Run Code Online (Sandbox Code Playgroud)
由于创建属性只需要 getter,因此您可以单独指定它,然后将旧属性与 setter 结合起来创建一个新属性。
foo = property(foo_get)
foo = foo.setter(foo_set)
Run Code Online (Sandbox Code Playgroud)
装饰器语法允许您跳过显式命名 getter 和 setter:
# Instead of foo = property(foo_get), define a function named foo,
# pass it to property, and rebind the name foo to the new property
@property
def foo(self):
...
# Instead of foo.setter(foo_set), define *another* function named foo,
# pass it too foo.setter, and rebind the name foo to the new, augmented property. Note that this works because Python will evaluate `@foo.setter` to
# get a reference to the bound property method
# before it evaluates the following def statement.
@foo.setter
def foo(self, v):
...
Run Code Online (Sandbox Code Playgroud)