有时候,我们希望对对象的属性有更强的控制:比如希望某个值在一定的范围内(比如温度,年龄等),或者希望赋值的时候要是某个类型的值,再比如希望某个值根据另外的属性值动态地调整(表示身体健康状况的属性要根据体温变化)。那么我们可以使用 python 的 property 装饰器。
以上是比较官方的说明,如果你对Java
有了解,那么应该知道Java
中属性都是私有的,对外提供 getter
、setter
方法。python
的property 装饰器也类似与此,只不过封装后的函数或者方法
不再通过函数名()
来访问,而是直接像属性
一样使用。
一、怎么使用 @property装饰器
例如:
class Person:
def __init__(self, age, create_date):
self._age = age
# Getter 方法
@property
def age(self):
return self._age
# Setter 方法
@age.setter
def age(self, value):
if not isinstance(value, int):
raise TypeError('期望是一个 int')
self._age = age
# Deleter 方法
@age.deleter
def age(self):
raise AttributeError("这个属性不能删除")
if __name__ == '__main__':
person = Person(29)
# 这里可以使用访问属性的方式来使用方法 `age`
print(person.age)
上述中我们 方法 age
使用了@property,它可以像普通属性一样获取,或者赋值。
上述代码中有三个相关联的方法,这三个方法的名字都必须一样。 第一个方法是一个 getter 函数,它使得 age 成为一个属性。 其他两个方法给 age 属性添加了 setter 和 deleter 函数。
也可以只封装
getter 函数
,需要强调的是只有在 age 属性被创建后, 后面的两个装饰器 @age.setter 和 @age.deleter 才能被定义。
二、什么时候使用 @property装饰器
1. 属性发生变化
假如你定义类Person
是这样的
class Person:
def __init__(self, age, create_date):
self.age = age
self.create_date = create_date
if __name__ == '__main__':
person = Person(29, date(1990,9,9))
# 这里直接访问对象属性
print(person.age)
一段时间后,你突然想起来,不应该直接获取Person
的age
属性,因为年龄是随着时间变化而变化的,我们应该提供一个get_age()
方法,可是代码中有很多地方已经在使用person.age
,这个时候我们可以使用@property装饰器
封装age
,而别处使用person.age
的地方就会转用新封装的方法。
2.为了语法简洁
python
提倡简洁的语法,它认为名词
就应该可以像属性一样直接访问,而动词才封装成方法。
例如你封装了一个网络对象client
,它具有 url
如果像下面两种写法,有人就是认为第二种更舒服。特别在函数的链式调用中。
parse(client.get_url())
parse(client.url)