數據封裝、繼承和多態只是面向對象編程中最基礎的3個概念。html
下面整理面向對象高級編程的更爲強大的技巧。python
使用__slots__:Python屬於動態語言,能夠容許已建立好的類動態地綁定任何屬性和方法。可是,給實例綁定後,由該類建立的其餘其餘實例是沒有綁定的;不過,能夠給類綁定,那麼有該類建立的實例均會擁有該屬性和方法。編程
>>> class Student(object): ... pass ...
>>> s = Student() >>> s.name = 'Michael' # 動態給實例綁定一個屬性 >>> print s.name Michael
>>> def set_age(self, age): # 定義一個函數做爲實例方法 ... self.age = age ... >>> from types import MethodType >>> s.set_age = MethodType(set_age, s, Student) # 給實例綁定一個方法 >>> s.set_age(25) # 調用實例方法 >>> s.age # 測試結果 25
>>> def set_score(self, score): ... self.score = score ... >>> Student.set_score = MethodType(set_score, None, Student)
同時,正由於動態語言的這種特性,爲了不過於屬性綁定,class類中使用__slots__來限制容許的屬性。app
>>> class Student(object): ... __slots__ = ('name', 'age') # 用tuple定義容許綁定的屬性名稱 ...
>>> s = Student() # 建立新的實例 >>> s.name = 'Michael' # 綁定屬性'name' >>> s.age = 25 # 綁定屬性'age' >>> s.score = 99 # 綁定屬性'score' Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: 'Student' object has no attribute 'score'
__slots__屬性只對父類起做用,但繼承的子類是不起做用的,除非子類中也定義__slots__,這樣,子類容許定義的屬性就是自身的__slots__加上父類的__slots__。函數
使用@property裝飾器:學習
在實際使用中,爲了檢查修改參數的合法性,會定義一個get和set函數,對set函數進行一系列的嚴格驗證。測試
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
>>> s = Student() >>> s.set_score(60) # ok! >>> s.get_score() 60 >>> s.set_score(9999) Traceback (most recent call last): ... ValueError: score must between 0 ~ 100!
爲了簡化上述調用和設置的過程,將兩個方法直接變成調用屬性同樣簡單,使用@property裝飾器。spa
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
>>> s = Student() >>> s.score = 60 # OK,實際轉化爲s.set_score(60) >>> s.score # OK,實際轉化爲s.get_score() 60 >>> s.score = 9999 Traceback (most recent call last): ... ValueError: score must between 0 ~ 100!
就能像調用普通屬性同樣方便了!設計
也能夠只定義只讀屬性:3d
class Student(object): @property def birth(self): return self._birth @birth.setter def birth(self, value): self._birth = value @property def age(self): return 2014 - self._birth
在繼承時,因爲對象會有多個屬性,通常按照繼承關係來講,選取其中一個大的類別做爲主線,即主線是單一繼承下來的。除主線外,其餘的屬性能夠做爲功能,多重繼承下來。這種設計稱爲Mixin。
例如,下面中,Mammal和Bird做爲主線,Runnable和Flyable做爲Mixin功能增長進去,構成多重繼承。
class Animal(object): pass # 大類: class Mammal(Animal): pass class Bird(Animal): pass
class Runnable(object): def run(self): print('Running...') class Flyable(object): def fly(self): print('Flying...')
class Dog(Mammal, Runnable): pass
class Bat(Mammal, Flyable): pass
以前提到過的以雙下劃線開頭和結尾的屬性,是屬於特殊屬性,它們是用來定製類的。
__str__():顯示print該類的實例的名稱
>>> class Student(object): ... def __init__(self, name): ... self.name = name ... def __str__(self): ... return 'Student object (name: %s)' % self.name ... >>> print Student('Michael') Student object (name: Michael)
__repr__():直接顯示變量
class Student(object): def __init__(self, name): self.name = name def __str__(self): return 'Student object (name=%s)' % self.name __repr__ = __str__ >>>s = Student('Michael') >>>s Student object (name: Michael)
__iter__():服務於for...in的迭代循環,該方法返回一個迭代對象,而後,Python的for循環會一直調用next()方法獲得循環的下一個值,直到遇到StopIteration錯誤後退出循環。
lass Fib(object): def __init__(self): self.a, self.b = 0, 1 # 初始化兩個計數器a,b def __iter__(self): return self # 實例自己就是迭代對象,故返回本身 def next(self): self.a, self.b = self.b, self.a + self.b # 計算下一個值 if self.a > 100000: # 退出循環的條件 raise StopIteration(); return self.a # 返回下一個值
>>> for n in Fib(): ... print n ... 1 1 2 3 5 ... 46368 75025
__getitem__():容許像list同樣按索引取值和切片。
class Fib(object): def __getitem__(self, n): if isinstance(n, int): a, b = 1, 1 for x in range(n): a, b = b, a + b return a if isinstance(n, slice): start = n.start stop = n.stop a, b = 1, 1 L = [] for x in range(stop): if x >= start: L.append(a) a, b = b, a + b return L
>>> f = Fib() >>> f[0] 1 >>> f[1] 1 >>> f[2] 2 >>> f[3] 3 >>> f[10] 89 >>> f[100] 573147844013817084101
>>> f = Fib() >>> f[0:5] [1, 1, 2, 3, 5] >>> f[:10] [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
__getattr__():當調用類的屬性或者方法不存在時,運行__getattr__()方法。
class Student(object): def __init__(self): self.name = 'Michael' def __getattr__(self, attr): if attr=='score': return 99
>>> s = Student() >>> s.name 'Michael' >>> s.score 99
__call__():對實例自己進行調用時,啓用該方法。
class Student(object): def __init__(self, name): self.name = name def __call__(self): print('My name is %s.' % self.name)
>>> s = Student('Michael') >>> s() My name is Michael.
經過callable()函數,能夠判斷一個對象是不是「可調用」對象。
更多定製類的方法,參考Python文檔
注:本文爲學習廖雪峯Python入門整理後的筆記