与经典的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

当前回答

简单的答案是: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主题。

其他回答

简单的答案是: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主题。

使用属性可以让您从普通的属性访问开始,然后在必要时使用getter和setter对其进行备份。

我认为两者都有各自的地位。使用@property的一个问题是,很难在子类中使用标准的类机制扩展getter或setter的行为。问题是实际的getter/setter函数隐藏在属性中。

你可以掌握这些函数,比如

class C(object):
    _p = 1
    @property
    def p(self):
        return self._p
    @p.setter
    def p(self, val):
        self._p = val

你可以像C.p.fset和C.p.fset一样访问getter和setter函数,但是你不能很容易地使用普通的方法继承(例如super)工具来扩展它们。在深入研究了super的复杂性之后,你确实可以这样使用super:

# Using super():
class D(C):
    # Cannot use super(D,D) here to define the property
    # since D is not yet defined in this scope.
    @property
    def p(self):
        return super(D,D).p.fget(self)

    @p.setter
    def p(self, val):
        print 'Implement extra functionality here for D'
        super(D,D).p.fset(self, val)

# Using a direct reference to C
class E(C):
    p = C.p

    @p.setter
    def p(self, val):
        print 'Implement extra functionality here for E'
        C.p.fset(self, val)

然而,使用super()是相当笨拙的,因为必须重新定义属性,并且必须使用稍微违反直觉的super(cls,cls)机制来获得p的未绑定副本。

在Python中,你不会仅仅为了好玩而使用getter或setter或属性。首先只使用属性,然后在需要时,最终迁移到属性,而不必使用类更改代码。

确实有很多带有.py扩展名的代码在任何地方都使用getter和setter、继承和无意义的类,例如一个简单的元组就可以了,但这是人们使用Python用c++或Java编写的代码。

这不是Python代码。

在大多数情况下,我宁愿两者都不使用。属性的问题是它们使类不那么透明。特别是,如果要从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.')

或类似帐户。保存方法。

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