与经典的getter+setter相比,@property表示法有什么优点?在哪些特定的情况下,程序员应该选择使用其中一种而不是另一种?

属性:

class MyClass(object):
    @property
    def my_attr(self):
        return self._my_attr

    @my_attr.setter
    def my_attr(self, value):
        self._my_attr = value

没有属性:

class MyClass(object):
    def get_my_attr(self):
        return self._my_attr

    def set_my_attr(self, value):
        self._my_attr = value

当前回答

对我来说,使用属性更直观,更适合大多数代码。

比较

o.x = 5
ox = o.x

vs.

o.setX(5)
ox = o.getX()

对我来说很明显,更容易理解。此外,属性允许私有变量更容易。

其他回答

在复杂的项目中,我更喜欢使用带有显式setter函数的只读属性(或getter):

class MyClass(object):
...        
@property
def my_attr(self):
    ...

def set_my_attr(self, value):
    ...

在长期存在的项目中,调试和重构比编写代码本身花费更多的时间。使用@property有几个缺点。Setter,使调试更加困难:

1) python允许为现有对象创建新属性。这使得下面的打印错误很难追踪:

my_object.my_atttr = 4.

如果你的目标是一个复杂的算法,那么你将花费相当多的时间试图找出它不收敛的原因(注意上面一行中额外的“t”)

2) setter有时可能演变成一个复杂而缓慢的方法(例如击中数据库)。对于另一个开发人员来说,很难弄清楚为什么下面的函数非常慢。他可能会花很多时间分析do_something()方法,而my_object。My_attr = 4。其实是减速的原因:

def slow_function(my_object):
    my_object.my_attr = 4.
    my_object.do_something()

在大多数情况下,我宁愿两者都不使用。属性的问题是它们使类不那么透明。特别是,如果要从setter引发异常,这是一个问题。例如,如果您有一个帐户。电子邮件属性:

class Account(object):
    @property
    def email(self):
        return self._email

    @email.setter
    def email(self, value):
        if '@' not in value:
            raise ValueError('Invalid email address.')
        self._email = value

这样,类的用户就不会期望给属性赋值会导致异常:

a = Account()
a.email = 'badaddress'
--> ValueError: Invalid email address.

结果,异常可能得不到处理,或者在调用链中传播得太高而无法正确处理,或者导致向程序用户提供非常无用的回溯(遗憾的是,这在python和java世界中太常见了)。

我也会避免使用getter和setter:

因为提前为所有属性定义它们非常耗时, 使代码的数量不必要地变长,这使得理解和维护代码更加困难, 如果只在需要时为属性定义它们,类的接口将会改变,损害类的所有用户

而不是属性和getter /setter,我更喜欢在定义良好的地方执行复杂的逻辑,例如在验证方法中:

class Account(object):
    ...
    def validate(self):
        if '@' not in self.email:
            raise ValueError('Invalid email address.')

或类似帐户。保存方法。

请注意,我并不是想说在任何情况下属性都是有用的,只是说如果您可以使您的类足够简单和透明,以至于您不需要它们,那么您可能会更好。

我很惊讶没有人提到属性是描述符类的绑定方法,Adam Donohue和NeilenMarais在他们的帖子中得到了这个想法——getter和setter是函数,可以用于:

验证 改变数据 鸭子类型(强迫类型到另一种类型)

这提供了一种聪明的方法来隐藏实现细节和代码cruft,如正则表达式,类型转换,尝试..块、断言或计算值除外。

一般来说,在对象上执行CRUD可能相当简单,但请考虑将持久化到关系数据库的数据示例。ORM可以在属性类中定义的绑定到fget, fset, fdel的方法中隐藏特定SQL白话的实现细节,该属性类将管理可怕的if ..elif . .在OO代码中是如此丑陋的梯子——暴露了简单而优雅的自我。variable = something,为使用ORM的开发人员消除细节。

如果有人认为属性只是束缚和纪律语言(即Java)的一些沉闷的残余,那么他们就没有理解描述符的意义。

我觉得属性是为了让您在真正需要getter和setter时才编写它们。

Java编程文化强烈建议永远不要授予对属性的访问权,相反,只访问实际需要的getter和setter。 总是编写这些显而易见的代码段有点啰嗦,请注意,70%的情况下,它们从未被一些重要的逻辑所取代。

在Python中,人们实际上关心这种开销,因此您可以采用以下实践:

不使用getter和setter在第一次,如果他们不需要 使用@property来实现它们,而不改变其余代码的语法。

简单的答案是:properties轻松获胜。总是这样。

有时需要getter和setter,但即使这样,我也会将它们“隐藏”到外部世界。在Python中有很多方法可以做到这一点(getattr, setattr, __getattribute__,等等…,但最简洁明了的是:

def set_email(self, value):
    if '@' not in value:
        raise Exception("This doesn't look like an email address.")
    self._email = value

def get_email(self):
    return self._email

email = property(get_email, set_email)

下面是一篇简短的文章,介绍Python中的getter和setter主题。