@property最主要的功能就是负责把一个方法变成属性调用。
那么在实际应用中,我们具体怎么使用呢?
1. 把一个方法变成属性调用
有时,我们在定义一个类时,需要设置私有属性,外部可以访问,但是不希望外部对属性进行更改。
class Person(object):
def __init__(self):
self._name = "小明" # 但下划线开头表示这是私有属性,但是外部依然可以访问更改
self._age = 18
self._gender = "男"
# 查看私有属性
person_1 = Person()
print(person_1._name)
print(person_1._age)
print(person_1._gender)
小明
18
男
# 对私有属性进行修改
person_2 = Person()
person_2._name = "小红"
print(person_2._name)
print(person_2._age)
print(person_2._gender)
小红
18
男
可以通过@property的方法来进行设置。这样可以隐藏属性名,让用户进行使用的时候无法随意修改。
class Person(object):
def __init__(self):
self._name = "小明"
self._age = 18
self._gender = "男"
@property
def name(self):
return self._name
@property
def age(self):
return self._age
@property
def gender(self):
return self._gender
person_1 = Person()
# 通过调用方法的方式查看属性,使用者不需要知道属性值,只需要知道该方法
print(person_1.name) # 使用调用属性的方式调用方法,后面不需要加()
print(person_1.age)
print(person_1.gender)
小明
18
男
修饰方法,使方法可以像属性一样访问
class Person(object):
def __init__(self):
self._name = "小明"
def get_age(self): # 调用该方法时需要加()
return 18
@property # 可以用调用属性的方法调用该方法,不需要加()
def get_gender(self):
return "男"
person_1 = Person()
print(person_1._name)
age = person_1.get_age() # 没有@property调用方法需要加()
print(age)
gender = person_1.get_gender # 有了@property调用方法不需要加()
print(gender)
小明
18
男
此时,我的疑惑是将方法当作属性一样访问能有什么好处呢?看了以下代码就明白了
class Person(object):
def __init__(self,name,age,gender=None):
self._name = name
self._age = age
self._gender = gender
person_1 = Person("小明","男性")
name = person_1._name
age = person_1._age
print("{}的年龄是:{}".format(name,age))
小明的年龄是:男性
以上的代码在设置年龄时并没有检查年龄的类型,所以"男性"被当作年龄赋值给了age。为了避免这个错误,我们在设置属性值的时候,需要添加一个set方法,用来检查输入的属性值是否正确
class Person(object):
def __init__(self,name=None,age=None,gender=None):
self._name = name
self._age = age
self._gender = gender
def set_age(self,age): # 设置年龄属性
if isinstance(age,int):
self._age = age
else:
raise ValueError("请输入int类型")
def get_age(self): # 获取年龄
return self._age
person_1 = Person("小明")
age_set = person_1.set_age("男性") # 输入错误的age类型
name = person_1._name
age = person_1.get_age()
print("{}的年龄是:{}".format(name,age))
ValueError Traceback (most recent call last)
<ipython-input-100-d071f5fc5e66> in <module>()
1 person_1 = Person("小明")
----> 2 age_set = person_1.set_age("男性")
3 name = person_1._name
4 age = person_1.get_age()
5 print("{}的年龄是:{}".format(name,age))
<ipython-input-98-b6d73e549a9e> in set_age(self, age)
10 return self._age
11 else:
---> 12 raise ValueError("请输入int类型")
13
14 def get_age(self):
ValueError: 请输入int类型
person_1 = Person("小明")
age = person_1.set_age(18)
name = person_1._name
print("{}的年龄是:{}".format(name,age))
小明的年龄是:18
以上的代码虽然正确,但是不是很麻烦,设置年龄需要person_1.set_age()
,获取年龄需要 age = person_1.get_age()
,如果使用@property方法呢?
使用@property对以上代码进行修改
class Person(object):
def __init__(self,name=None,age=None,gender=None):
self._name = name
self._age = age
self._gender = gender
@property # 读取age,相当于上面的get_age方法
def age(self):
return self._age
@age.setter # 设置age,相当于上面的set_age方法
def age(self,age):
if isinstance(age,int):
self._age = age
else:
raise ValueError("请输入int类型")
person_1 = Person("小明")
person_1.age = "男性" # 注意虽然用调用属性的方式调用age方法,但是调用的仍是age()方法,不是._age
name = person_1._name
age = person_1.age
print("{}的年龄是:{}".format(name,age))
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
<ipython-input-102-c3769d8541af> in <module>()
1 person_1 = Person("小明")
----> 2 person_1.age = "男性"
3 name = person_1._name
4 age = person_1.age
5 print("{}的年龄是:{}".format(name,age))
<ipython-input-101-c21e1cb55869> in age(self, age)
14 self._age = age
15 else:
---> 16 raise ValueError("请输入int类型")
ValueError: 请输入int类型
person_1 = Person("小明")
person_1.age = 18
age = person_1.age
name = person_1._name
print("{}的年龄是:{}".format(name,age))
小明的年龄是:18
以上我们看出,@property装饰的作用下,设置和获取属性时我们只需要person_1.age
来实现,是不是简单很多呢?