Python有一些定製類的特殊方法,如__str__()
、__iter__()
、__getitem__()
,其中一些具備動態特性的方法能夠用來很方便地處理某些動態情況。python
When I see a bird that walks like a duck and swims like a duck and quacks like a duck, I call that bird a duck.程序員
duck-typing
是一種編程風格,它的含義是:一個對象的語義,不是因爲它繼承自特定的類或者實現某個接口,而是由它的屬性和方法的集合所決定。也就是說,咱們在使用一個對象的時候,不在意它是什麼類型、是否實現了特定的接口,而是在乎它有沒有咱們須要的屬性和方法。
其實這就是在沒有語言約束的狀況下來實現多態,不像C++使用繼承和虛函數在語言上設置約束來實現多態,因此就須要程序員來進行約束,好的文檔、代碼、測試都是很須要的。
在用該風格編碼時不要使用像type()
、isintance()
這樣的方法去測試函數中參數的類型,而是直接使用參數來表述行爲,若是該參數沒有應有的屬性或方法,就會報錯。
使用__getitem__()
來使本身的類表現得和Python內建的list
、tuple
、dict
同樣時,就依靠了這種風格,下面給出Wiki上關於duck-typing
的Python示例代碼:編程
class Duck: def quack(self): print("Quaaaaaack!") def feathers(self): print("The duck has white and gray feathers.") class Person: def quack(self): print("The person imitates a duck.") def feathers(self): print("The person takes a feather from the ground and shows it.") def name(self): print("John Smith") def in_the_forest(duck): duck.quack() duck.feathers() def game(): donald = Duck() john = Person() in_the_forest(donald) in_the_forest(john) game()
in_the_forest(duck)
方法無論duck參數是Duck類型仍是Person類型,只要該類型的實例由quack和feathers方法就能夠。函數
__getattr__
,當調用不存在的屬性時,若是存在__getattr__
方法,就會調用__getattr
方法來嘗試得到屬性。測試
__call__
,使實例自己變成可調用的。
這種徹底動態的調用能夠應對一些動態狀況,例如實現REST API。編碼
class Chain(object): def __init__(self, path=''): self._path = path def __getattr__(self, path): return Chain('%s/%s' % (self._path, path)) def __str__(self): return self._path def __call__(self, attr): return Chain('%s/%s' % (self._path, attr))
這樣咱們就不用給每一個URL對應的API寫方法了,採用鏈式的調用就能夠,如schools/status/users
,就能夠用Chain().schools.status.users
。某些REST API會在URL中添加參數,如/schools/users/ID/report
,其中ID
就是一個參數,是某個學生實際的學號,這時就能夠利用__call__
將對象變成可調用的,即可完成此功能,調用方式就是Chain().schools.users(ID).report
。rest
廖雪峯的Blogcode