使用__slots__
我们可以为类的实例动态绑定任意属性,但是如果我们想要限制实例的属性怎么办?比如,只允许对Student实例添加name和age属性。这时我们就可以用__slots__变量。
class Student(object):
__slots__ = ('name', 'age')# 用tuple定义允许绑定的属性名称
if __name__=='__main__':
stu = Student()
print(stu)
stu.sex = 'man'
运行将会报错:
Exception has occurred: exceptions.AttributeError
'Student' object has no attribute 'sex'
File "/Users/fww/Documents/hellopython/hello.py", line 15, in <module>
注意:slots__定义的属性仅对当前类实例起作用,对继承的子类是不起作用的,
除非在子类中也定义__slots,这样,子类实例允许定义的属性就是自身的__slots__加上父类的__slots__:
class GraduateStudent(Student):
pass
if __name__=='__main__':
stu = GraduateStudent()
print(stu)
stu.sex = 'man'
print(stu.sex)
运行结果:
<__main__.GraduateStudent object at 0x10b767a00>
man
而如果子类也加了__slots__ :
class Student(object):
__slots__ = ('name', 'age')
class GraduateStudent(Student):
__slots__ = ('graduateYear')
if __name__=='__main__':
stu = GraduateStudent()
print(stu)
stu.name = 'Tom'
stu.age = 18
stu.graduateYear = '2018'
print(stu.name)
print(stu.age)
print(stu.graduateYear)
运行结果:
<__main__.GraduateStudent object at 0x10688e3f8>
Tom
18
2018
使用@property
我们在绑定属性时,如果直接把属性暴露出去,虽然写起来很简单,但是,没办法检查参数,导致属性可以随意更改;因此我们使用了私有属性,通过get、set方法对属性进行操作,这样可以在对应的方法中对参数做检查。然而我们又希望在使用的时候能够简单,那么有没有两全其美的方法呢?答案就是@property装饰器。
Python内置的@property装饰器就是负责把一个方法变成属性调用的。
class Student(object):
__slots__ = ('name', 'age','__sex')
@property
def sex(self):
return self.__sex
@sex.setter
def sex(self, value):
if cmp(value, 'man')==0 or cmp(value, 'women')==0:
self.__sex = value
else:
raise ValueError('bad sex')
要验证结果,只需要给一个错误的值就可以了:
if __name__=='__main__':
stu = Student()
print(stu)
stu.sex = 'boy'
print(stu.sex)
结果:
Exception has occurred: exceptions.ValueError
bad sex
File "/Users/fww/Documents/hellopython/hello.py", line 20, in sex
File "/Users/fww/Documents/hellopython/hello.py", line 26, in <module>
可以看到,类型检查起到了作用。
把一个getter方法变成属性,只需要加上@property就可以了,此时,@property本身又创建了另一个装饰器@score.setter,负责把一个setter方法变成属性赋值,于是,我们就拥有一个可控的属性操作。
定义只读属性
只定义getter方法,不定义setter方法就是一个只读属性:
@property
def school(self):
return '北京大学'
运行:
print(stu.school)
结果:
<__main__.Student object at 0x10a9e7518>
北京大学
而,如果想修改school属性:
stu.school = '清华大学'
则会报错:
Exception has occurred: exceptions.AttributeError
can't set attribute
File "/Users/fww/Documents/hellopython/hello.py", line 30, in <module>
小结:@property广泛应用在类的定义中,可以让调用者写出简短的代码,同时保证对参数进行必要的检查,这样,程序运行时就减少了出错的可能性。