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

2024-04-26 02:52:52 发布

您现在位置:Python中文网/ 问答频道 /正文

我想不通为什么getter/setter方法的名称必须与属性的名称相同。你知道吗

我试过阅读亚伦霍尔的答案here,但是我仍然找不到一个解释(或者没有找到解释)来解释为什么我们必须使用各自的名字。你知道吗

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 

编辑: 我发现令人困惑的是,如果我将我的方法重命名为:

@model.setter
def model_new(self, new_model): 
    if new_model == 'Audi':
        raise ValueError ('NO AUDI ALLOWED')
    else:
        self.current_model = new_model

我试着跑步:

audi = Car()
audi.model = 'BMW' # will get AttributeError: can't set attribute

我认为这不起作用,因为getter、setter和deleter方法创建了属性的副本,而更改方法的名称就像修改其他属性的属性一样。就像这样:模型=模型设定器(型号)。你知道吗

但我不确定我是否理解正确


Tags: 方法self名称newmodelreturnif属性
2条回答

简而言之:他们不必这样做,但建议这样做。你知道吗

如果我对你的问题理解正确,你想知道为什么命名是个好习惯

class Car(object):
    def __init__(self, color='blue', model='Opel'):
        self.color = color
        self._current_model = model

    @property
    def model(self):                               #THIS FUNCTION...
        return self._current_model 

    @model.setter                                  
    def model(self, new_model):                    #...LIKE THIS FUNCTION
        if new_model == 'Audi':
            raise ValueError ('NO AUDI ALLOWED')
        else:
            self._current_model = new_model

这样做是一个好主意,因为它避免了混淆,并且与定义属性的第二种方法一致。请考虑以下代码段:

class Car:

    def __init__(self, color='blue', model='Opel'):
        self.color = color
        self._current_model = model

    def g(self):
        print('Getting value')
        return self._current_model

    def s(self, model):
        print('Setting value')
        self._current_model = model

    def d(self):
        print('Deleting value')
        del self._current_model

    prop = property(g, s, d)

您可以为获取、设置、删除等定义一个单独的函数,并使用它们创建属性类的实例。现在可以通过以下函数修改隐藏变量

my_car = Car();
my_car.prop = 'BMW'      #call the setter
print(my_car.prop)       #call the getter
del my_car.prop          #call the deleter

这是干净的,你知道你正在处理的变量。作为反例,请看以下代码段:

class Car:

    def __init__(self, color='blue', model='Opel'):
        self.color = color
        self._current_model = model

    @property
    def g(self):
        print('Getting value')
        return self._current_model

    @g.setter
    def s(self, model):
        print('Setting value')
        self._current_model = model

    @g.deleter                         # this could be s.deleter as well
    def d(self):
        print('Deleting value')
        del self._current_model

如您所见,与属性相比,setter和deleter可能使用不同的名称。如果您尝试执行与以前相同的操作,则最终会产生难以理解的代码:

mycar = Car();
mycar.s = 'BMW'
print(mycar.g)
del mycar.d

您似乎使用了3个属性来修改隐藏变量。这会不必要地污染命名空间,通常不建议这样做。因此,坚持使用单一名称是有意义的,这与以前的属性定义是一致的。你知道吗

函数名必须相同,因为@model.setter不更新现有属性;它用基于现有属性的新属性替换它。当您将属性方法用作修饰符时,属性的名称是最后修饰的函数的名称。你知道吗

记住

@model.setter
def model(self, new_model): 
    if new_model == 'Audi':
        raise ValueError ('NO AUDI ALLOWED')
    else:
        self.current_model = new_model

大致相当于

def tmp(self, new_model): 
    if new_model == 'Audi':
        raise ValueError ('NO AUDI ALLOWED')
    else:
        self.current_model = new_model

model = model.setter(tmp)

也就是说,由def语句(model)绑定的名称被绑定到model.setter的结果。如果使用不同的名称,则更改了属性的名称。你知道吗


简单的方法是同时提供getter(以及可选的setter和deleter):

def foo_get(self):
    ...

def foo_set(self, v):
    ...

foo = property(foo_get, foo_set)

由于创建属性只需要getter,因此可以单独指定它,然后将旧属性与setter组合创建一个新属性。你知道吗

foo = property(foo_get)
foo = foo.setter(foo_set)

decorator语法允许您跳过显式命名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):
    ...

相关问题 更多 >

    热门问题