python - python @property和获取和设置

  显示原文与译文双语对照的内容

下面是一个纯Python-specific设计问题:


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

 def set_my_attr(self, value):
. . .


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

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

python 让我们可以这样做。 如果你要设计一个 python 程序,你会使用什么方法,为什么?

时间:

简短的回答是:的属性赢得了 hands 。 总是。

有时候需要使用getter和 setter,但即使是这样,我也会将它们"隐藏"。 在 python ( getattrsetattr__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。

我认为两者都有自己的位置。 使用 @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

你可以访问getter和setter函数作为 C.p.fgetC.p.fset,但是你不能很容易地使用普通方法继承( 例如。 用于扩展它们的功能。 挖掘一些错综复杂的超级之后,你确实可以使用超级以这种方式:


# 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() 是相当麻烦的,因为必须重新定义属性,并且你必须使用稍微 counter-intuitive super(cls,cls) 机制来获得未绑定的的绑定。

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

比较


o.x = 5
ox = o.x

vs 。


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

对我来说更容易阅读。 也允许私有变量更容易使用。

我宁愿在大多数情况下都不使用。 属性的问题是它们使类变得不透明。 尤其是,如果你从setter引发异常,这是个问题。 例如如果你有一个 Account.email 属性:


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.')

或者类似的Account.save 方法。

注意,我并不是在说,没有情况下属性是有用的,只是你可能会更好,如果你可以让你的类足够简单和透明的,你不需要他们。

...