前言
養成一個好的習慣只需要堅持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
# 測試通過!