【问题标题】:python why is a setter preferred?python为什么首选setter?
【发布时间】:2018-03-10 20:52:37
【问题描述】:

属性装饰器是一种很好的方式来“保护”一个想要设置一次并且不再更改的属性。我通常以这种方式处理(顺便说一句,遵循here 的建议):

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'

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

我能想到的最好的解释是来自作者的一条消息,说“你不应该更改此属性,但如果你真的想要,有一种机制可以在不更改‘受保护’属性的情况下进行更改”。但是,python 并没有真正保护属性。

那么,重点是什么,哪个更符合 Python 风格,为什么?

【问题讨论】:

    标签: python properties setter


    【解决方案1】:

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

    例如,此类的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
    

    【讨论】:

    • 是否有理由使用operator.index() 而不是int()?编辑:对删除的响应的推荐(?)
    • 感谢您的用例!第二个是我通常最终得到的,虽然我通常不使用 setter,因为我的类主要描述物理对象(工程内容),并且在对象初始化时执行断言和健全性检查。
    【解决方案2】:

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

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

    注意:从技术上讲,getter 和 setter 不是 100% 等效于属性,因为没有 deleter,它在行为上与原始属性不同。但是在你的 API 中强制执行不可删除性是愚蠢的。在第三方类实例(或几乎任何实例)的随机属性上到处调用del obj.attr 的开发人员应该得到他们所得到的,你不应该以减慢和使正常使用复杂化为代价来防御这种废话模式。

    【讨论】:

    • name 的实际示例来自我将很快开始使用的模块。我明白你的意思:为进一步扩展做一些准备,但在有意义的地方做,即人们可以预期需要更强大的东西,这可能不是命名,除非你想限制名称等;也不要过度使用它。 (注意:我会接受@Blckknght 对其他用例和模式的回答。)
    猜你喜欢
    • 2014-02-23
    • 2016-12-28
    • 2017-02-04
    • 1970-01-01
    • 2018-04-08
    • 2016-10-18
    • 2010-09-13
    相关资源
    最近更新 更多