1. property的作用
在Python中,属性可以完成赋值、取值、删除的操作。如果我们想要在完成这些操作前,进行属性的校验工作(例如:赋值前判断数据的有效性、删除前判断合法性身份),则需要在方法中完成。
那么有没有既能检查参数,又可以用类似属性这样简单的方式来访问类的变量呢?
有的,我们可以通过property,来实现既能检查属性,还能用属性的方式来访问该属性的功能。
2. property的本质——property类
property()
的实例化方式:property(fget=None, fset=None, fdel=None, doc=None)
参数说明:
fget
: 用于获取属性值的函数fset
: 用于设置属性值的函数fdel
: 用于删除属性值的函数doc
: 文档字符串
根据上述说明,如果要对property类进行实例化,需要传入相关功能的函数。
class Person:
def __init__(self):
self.__age = 0
def get_age(self):
return self.__age
def set_age(self, num):
if num >= 18:
self.__age = num
else:
raise ValueError('Age below 18 is not possible.')
def del_age(self):
print('将要删除age属性')
del self.__age
# 对象age则是我们调用的属性,通过age可以完成获取、赋值、删除的操作
age = property(get_age, set_age, del_age)
person = Person()
# 获取属性值
print(person.age)
# 设置属性值
person.age = 19
print(person.age)
# 删除属性值
del person.age
3. 使用装饰器定义只读属性
@property
语法糖提供了比 property()
函数更简洁直观的写法。
Python内置的@property
装饰器可将一个方法变成属性调用。
并且得到是只读属性,也是得到是真正意义上的私有属性。我们无法通过赋值的方式,修改属性值。
(1)未使用property装饰的情况
# 未使用property装饰的情况
class Person:
def __init__(self):
self.__age = 0
def age(self):
return self.__age
# 调用方式
person = Person()
age = person.age()
print(age)
# 输出结果
"""
0
"""
(2)使用property装饰后的情况
# 使用property装饰后的情况
class Person:
def __init__(self):
self.__age = 0
@property
def age(self):
return self.__age
# 调用方式
person = Person()
age = person.age
print(age)
# 输出结果
"""
0
"""
4. 使用装饰器设置属性的方式
由于通过 @property
将方法变为只读属性。此时如果添加修改属性的方式,可以通过 @属性名.setter
方式来完成。
例如,在上述代码中,通过 @property
添加了一个 age
属性,接下来我们就可以使用 @age.setter
装饰同名的 age()方法
,添加赋值的功能。需要注意的是当前age()
方法的第二个参数用来接收值。操作方式如下:
在 Person
类中,创建同名的 age()
方法,第二个参数num
用来获取赋值参数,然后给该方法添加 @age.setter
装饰器,使得 age
属性拥有赋值操作。
class Person:
def __init__(self):
self.__age = 0
@property
def age(self):
return self.__age
@age.setter
def age(self, num):
if num >= 18:
self.__age = num
else:
raise ValueError('Age below 18 is not possible.')
# 调用
person = Person()
print(person.age)
person.age = 19
print(person.age)
person.age = 4
print(person.age)
# 输出结果
"""
0
19
Traceback (most recent call last):
File "/Users/bingyao/Desktop/面试题/code/tuple与list的区别.py", line 70, in <module>
person.age = 4
File "/Users/bingyao/Desktop/面试题/code/tuple与list的区别.py", line 60, in age
raise ValueError('Age below 18 is not possible.')
ValueError: Age below 18 is not possible.
"""
从打印结果来看,在给 age
赋值的时候,程序是执行了 raise ValueError('Age below 18 is not possible.')
。因此,想要通过方法完成类似于属性赋值的方式,通过 @属性.setter
是可以实现的。
5. 使用装饰器设置属性的删除操作
通过装饰器给属性设置删除操作的方式同赋值方式大致相同,唯一的却别就在于使用的是装饰器为 @属性名.deleter
通过此装饰器可以将方法变为方法名字的属性,来完成删除操作。
class Person:
def __init__(self):
self.__age = 0
@property
def age(self):
return self.__age
@age.setter
def age(self, num):
if num >= 18:
self.__age = num
else:
raise ValueError('Age below 18 is not possible.')
@age.deleter
def age(self): # 由于这里的方法名为age,所以要删除属性,需要使用age
print('将要删除age属性')
del self.__age
person = Person()
print(person.age)
person.age = 19
print(person.age)
del person.age
小结
(1) property
本质是一个类,通过给 property
提供不同的功能的函数,完成属性的改、查、删的操作。实例对象名字即为调用属性的名字。
(2) @property
广泛应用在类的定义中,可以让调用者写出简短的代码,同时保证对参数进行必要的检查,这样,程序运行时就减少了出错的可能性。
(3) @property
语法糖提供了比 property()
函数更简洁直观的写法。
- a. 被
@property
装饰的方法是获取属性值的方法,被装饰方法的名字会被用做属性名
。 - b. 被
@属性名.setter
装饰的方法是设置属性值的方法。 - c. 被
@属性名.deleter
装饰的方法是删除属性值的方法。