前言
手机QQ有一个根据条件查找陌生人的功能。我初中时挺爱玩儿的,也因此在好友列表里添加了不少女生,相隔十年,我不得不感谢当时做出英明决定的自己,因为现在浏览空间总能看到大量的美女自拍,爽歪歪……
……咳咳!不扯了,进入正题。
普通示例
既然我们要查找符合条件的陌生人,那当然得先构建一个具有这样条件的人出来,再去数据库中匹配真实用户。为了简便,这里我就只用到性别,年龄,职业。
根据要求,完成代码还不“洒洒水”呀!
class Stranger(object):
def __init__(self, gender=None, age=None, job=None):
self.gender = gender
self.age = age
self.jobb = job
if __name__ == "__main__":
# 创建一个“妹子”
meizi = Stranger()
# 设置妹子的属性
meizi.gender = "female"
meizi.age = 18
meizi.job = "teacher"
# 访问妹子的属性
print("妹子信息:")
print("性别:{gender}".format(gender=meizi.gender))
print("年龄:{age}".format(age=meizi.age))
print("职业:{job}".format(job=meizi.job))
# 输出:
#妹子信息:
#性别:female
#年龄:18
#职业:teacher
但是不对,因为如上我们定义的Stranger类,实例化出来的对象meizi还可以这样用:
# ...
if __name__ == "__main__":
# 创建一个“妹子”
meizi = Stranger()
# 设置妹子的属性
meizi.gender = "beijing"
meizi.age = "teacher"
meizi.job = 20
# 访问妹子的属性
print("妹子信息:")
print("性别:{gender}".format(gender=meizi.gender))
print("年龄:{age}".format(age=meizi.age))
print("职业:{job}".format(job=meizi.job))
# 输出:
#妹子信息:
#性别:beijing
#年龄:teacher
#职业:20
程序没有报异常,但输出结果乱了套。 怎么性别变beijing、年龄变teacher呢?
对属性赋值进行约束
这是因为我们没有对属性gender,age,job加以限制,所以可以被用户任意赋值。要约束自然不难,这里单拿属性age作说明:
class Stranger(object):
def __init__(self, gender=None, age=None, job=None):
self.gender = gender
self.age = age
self.jobb = job
# 设置age
def set_age(self, age):
if isinstance(age, int):
self.age = age
else:
raise ValueError("'int' type need")
# 读取age
def get_age(self):
return self.age
if __name__ == "__main__":
# 创建一个“妹子”
meizi = Stranger()
meizi.set_age(18)
print("年龄:{age}".format(age=meizi.get_age()))
# 输出:
#年龄:18
如果此时我们做这样的操作:
meizi.set_age("teacher")
print("年龄:{age}".format(age=meizi.get_age()))
程序会抛异常ValueError: 'int' type need
我们的确实现了预期的目的,但是设置age需要执行meizi.set_age("teacher")
,访问age需要meizi.get_age()
,是不是变麻烦呢?
@property的使用
为了避免麻烦,于是有了@property装饰器。它的作用是:将方法变成属性调用。使用示例如下:
class Stranger(object):
def __init__(self, gender=None, age=None, job=None):
self.gender = gender
self._age = age # 这里的成员属性_age需要与成员方法age()区分开
self.jobb = job
# 读取age
@property # 实现一个age相关的getter方法
def age(self):
return self._age
# 设置age
@age.setter # 实现一个age相关的setter方法
def age(self, value):
if isinstance(value, int):
self._age = value
else:
raise ValueError("'int' type need")
if __name__ == "__main__":
# 创建一个“妹子”
meizi = Stranger()
meizi.age = 18 # 使用时注意是.age,不是._age
print("年龄:{age}".format(age=meizi.age))
# 输出:
#年龄:18
注意事项:
- 属性名与方法名一定要区分开,不然会进入死循环(
self._age
,def age()
) - 实例化的对象使用属性时,不是调用属性(
),而是用的方法名(meizi._age
meizi.age
) - @property其实就是实现了getter功能; @xxx.setter实现的是setter功能;还有一个 @xxx.deleter实现删除功能
- 定义方法的时候 @property必须在 @xxx.setter之前,且二者修饰的方法名相同(
age()
) - 如果只实现了 @property(而没有实现@xxx.setter),那么该属性为 只读属性
@property原理
函数接口:property(fget=None, fset=None, fdel=None, doc=None)
使用:
class Stranger(object):
def __init__(self, gender=None, age=None, job=None):
self.gender = gender
self._age = age
self.jobb = job
# 设置_age
def set_age(self, age):
if isinstance(age, int):
self._age = age
else:
raise ValueError("'int' type need")
# 读取_age
def get_age(self):
return self._age
# 使得实例化对象可以利用.age方式来访问
age = property(get_age, set_age)
if __name__ == "__main__":
# 创建一个“妹子”
meizi = Stranger()
meizi.age = 18
print("年龄:{age}".format(age=meizi.age))
# 输出:
#年龄:18
还不快抢沙发