为什么 getter/setter 方法必须与原始属性的名称相同?

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)。

但我不确定我是否正确理解了这一点

che*_*ner 5

函数名称需要相同,因为@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)