前言
养成一个好的习惯只需要坚持21天,Day11
这两天主要学习一下面向对象的高级编程。
使用__slots__
由之前学习类的定义和实例的创建,我们可以给实例绑定不同的属性,例如:
class Student(object):
pass
s = Student()
s.name = 'Tom' # 动态给实例绑定一个属性
print(s.name)
# Tom
如果我们只允许对Student实例添加name和age属性,达到限制的目的,我们就可以定义一个特殊的__solts__
变量,来限制该class实例能添加的属性,接下来Student实例就只能添加name和age属性了:
class Student(object):
__solts__ = ('name','age') #用tuple定义允许绑定的属性名称
接着进行测试:
s = Student() #创建新的实例
s.name = 'Tom' # 绑定name属性
s.age = 23 # 绑定age属性
s.score = 90 # 绑定score属性
# Traceback (most recent call last):
# File "<stdin>", line 1, in <module>
# AttributeError: 'Student' object has no attribute 'score'
由于score
属性没有被放到__solts__
中,所以不能绑定score
属性;如果强行绑定就会得到AttributeError
错误。不过__slots__
定义的属性仅对当前类实例起作用,对继承的子类是不起作用的。例如GraduateStudent子类是可以绑定score属性的:
class GraduateStudent(Student):
paa
g = GraduateStudent()
g.score = 999
print(g.score)
# 90
@property
在绑定属性的时候,我们需要对参数进行检查,比如上面在为对象的score属性赋值999时,显然是不符合我们生活中的分数的。为了限制score的范围,可以通过设置方法来获取和设置成绩,比如set_score()
和get_score()
方法:
class Student(object):
def get_score(self):
return self._score
def set_score(self, value):
if not isinstance(value, int):
raise ValueError('score must be an integer!')
if value < 0 or value > 100:
raise ValueError('score must between 0 ~ 100!')
self._score = value
如上定义后,就不能对score随意设值了。当赋予score的值不是int类型或者超过0-100时就会报错:
s = Student()
s.set_score(90)
print(s.get_score)
# 90
s.set_score(999)
# Traceback (most recent call last):
...
# ValueError: score must between 0 ~ 100!
这样的调用略显复杂,在Python中可以使用@property
装饰器负责把一个方法变成属性调用,即代替上面的功能:
class Student(object):
@property
def score(self):
return self._score
@score.setter
def score(self, value):
if not isinstance(value, int):
raise ValueError('score must be an integer!')
if value < 0 or value > 100:
raise ValueError('score must between 0 ~ 100!')
self._score = value
把一个getter方法变成属性,只需要加上@property
。此时,@property
本身又创建了另一个装饰器@score.setter
,负责把一个setter方法变成属性赋值,于是,我们就拥有一个可控的属性操作:
s = Student()
s.set_score(90)
print(s.score)
# 90
s.set_score(999)
# Traceback (most recent call last):
...
# ValueError: score must between 0 ~ 100!
下面的例子中birth
是可读写属性,而age
就是一个只读属性,因为age
可以根据birth
和当前时间计算出来。
class Student(object):
@property
def birth(self):
return self._birth
@birth.setter
def birth(self, value):
self._birth = value
@property
def age(self):
return 2015 - self._birth
练习
请利用@property
给一个Screen对象加上width和height属性,以及一个只读属性resolution:
class Screen(object):
@property
def width(self):
return self._width
@width.setter
def width(self,value):
if not isinstance(value,int):
raise ValueError('width must be integer')
if value < 0:
raise ValueError('width must be above 0')
self._width = value
@property
def height(self):
return self._height
@height.setter
def height(self,value):
if not isinstance(value,int):
raise ValueError('height must be integer')
if value < 0:
raise ValueError('height must be above 0')
self._height = value
@property
def resolution(self):
return self.width * self.height
# 测试:
s = Screen()
s.width = 1024
s.height = 768
print('resolution =', s.resolution)
if s.resolution == 786432:
print('测试通过!')
else:
print('测试失败!')
# resolution = 786432
# 测试通过!