Python中的属性
为什么要使用变量 self._age 呢?这个名字听起来和已经用过的 self.age 没什么关系,为什么不直接用 self.age 呢?
class newprops(object):
def getage(self):
return 40
def setage(self, value):
self._age = value
age = property(getage, setage, None, None)
4 个回答
4
你的例子其实没什么意义,因为这个获取器返回的是一个常量。通常情况下,带下划线的变量是和属性一起使用的,属性可以分为:
1) 只读
class C(object):
@property
def age(self):
return self._age
在这种情况下,instance.age
只能读取,不能赋值。按照惯例,内部会写入 self._age
。
2) 读写
class C(object):
@property
def age(self):
return self._age
@age.setter
def age(self, value):
assert value >= 0
self._age = value
只有在赋值时需要进行额外的计算或检查时,才有必要同时使用获取器和设置器。如果没有这些需求,你可以直接声明一个没有下划线的变量,因为属性和实例变量在代码中访问的方式是一样的。所以 _age
和属性 age
当然需要命名不同。
7
一些面向对象的编程语言有一种叫做私有属性,这种属性不能在类的方法外部访问。这很重要,因为有些属性不应该被直接修改,而是应该根据其他东西来改变,或者在改变之前需要进行验证。在Python中没有真正的私有属性,但你可以通过使用以下划线开头的变量来实现类似的效果,这就是Python对私有方法和属性的约定。
举个例子,直角三角形的斜边可以用公式h=sqrt(a*a+b*b)
来计算,所以你不能直接改变h
,因为这个关系必须保持一致。另外,比如说一个名字必须是LASTNAME COMMA FIRSTNAME
的格式,那么在你给self.lastname
赋值之前,你需要先验证这个格式是否正确。
属性的获取器让你可以获取斜边的值,但不允许你直接设置它。属性的设置器则允许你设置一个属性,但你可以在实际设置之前进行一些检查。
所以:
class Person(object)
def __init__(self):
# The actual attribute is _name
self._name = None
@property
def name(self):
# when I ask for the name, I mean to get _name
return self._name
@name.setter
def name(self, value):
# before setting name I can ensure that it has the right format
if regex_name.match(value):
# assume you have a regular expression to check for the name
self._name = value
else:
raise ValueError('invalid name')
另一个例子:
class Triangle(object):
def __init__(self, a, b):
# here a and b do not need to be private because
# we can change them at will. However, you could
# make them private and ensure that they are floats
# when they are changed
self.a = a
self.b = b
@property
def h(self):
return math.sqrt(a*a+b*b)
# notice there is no h.setter - you cannot set h directly
12
self.age
这个名字已经被属性占用了,所以你需要给实际的变量起个不同的名字,这里用的是_age
。
顺便说一下,从Python 2.6开始,你可以用装饰器来写这个:
def newprops(object):
@property
def age(self):
return 40
@age.setter
def age(self, value):
self._age = value