python 为什么 setter 是首选?

python why is a setter preferred?

属性 装饰器是 "protect" 属性的一种很好的方式,人们希望设置一次,就再也不会改变。我通常这样处理(顺便说一句,遵循建议):

self._name = 'foo'

@property
def name(self):
    return self._name

因此尝试直接设置名称会产生 AttributeError。

然而,我经常看到以下模式:

@name.setter
def name(self, value):
    self._name = value

@property
def name(self):
    return self._name

这似乎有点违反直觉,因为它正是我想要避免的,并且需要额外的编码,即理论上

self.name = 'bar'

就足够了,尽管很明显这是处理问题的最糟糕方法。

我能想到的最好的解释是来自作者的消息 "you should not change this attribute but if you really want to, there is a mechanism to do it without changing a 'protected' attribute"。但是,python 并没有真正保护属性。

那么,有什么意义呢,哪个更 pythonic,为什么?

如果settergetter只是直接读写受保护的变量,那么它们是没有意义的,使用它不是Pythonic;它只是在每次访问的 property 开销上浪费时间。该属性应该只设为 public 并删除 属性。

属性的优点是当您需要用更强大的东西替换那个简单的 public 属性时,因为您可以制作一个 属性 继续 act 就像使用属性的代码一样,但也执行额外的工作。除非你有额外的工作,否则如果你允许它被写入,请坚持使用该属性。

注意:从技术上讲,getter 和 setter 并非 100% 等同于属性,因为没有 deleter,它在行为上与原始属性并不相同。但是在 API 中强制执行不可删除性是愚蠢的;在第三方 class 实例(或几乎任何实例)的随机属性上四处调用 del obj.attr 的开发人员理应得到他们的回报,您不应该以牺牲减慢并使正常使用模式复杂化。

如果您在 getter 或 setter 中没有做任何特殊的事情,那么没有充分理由使用 属性 是正确的。但是,如果您 想做一些特别的事情(比如验证新值,或以某种方式规范化它们),那么它就很有意义了。

例如,这个 class 的 foo 属性将始终夹在 01 之间(非数值会立即导致错误) :

class Foo:
    _foo = 1.0

    @foo
    def probability(self):
        return self._foo

    @foo.setter
    def foo(self, value):
        if value < 0:
            value = 0
        elif value > 1:
            value = 1
        self._foo = value

一个简单 setter 但复杂 getter 的示例可能是这样的(推迟可能不需要的昂贵初始化):

class Foo:
    _foo = None

    def initialize_foo(self):
        self._foo = some_expensive_calculation()

    @property
    def foo(self):
        if self._foo is None:
            self.initialize_foo() # need the default value
        return self._foo

    @foo.setter
    def foo(self, value):
        self._foo = value