Python動態特性應對動態狀況

Python有一些定製類的特殊方法,如__str__()__iter__()__getitem__(),其中一些具備動態特性的方法能夠用來很方便地處理某些動態情況。python

Duck-typing

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內建的listtupledict同樣時,就依靠了這種風格,下面給出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).reportrest

參考資料

相關文章
相關標籤/搜索