Python中的descriptor描述器簡明使用指南
當(dāng)定義迭代器的時(shí)候,描述是實(shí)現(xiàn)迭代協(xié)議的對象,即實(shí)現(xiàn)__iter__方法的對象。同理,所謂描述器,即實(shí)現(xiàn)了描述符協(xié)議,即__get__, __set__, 和 __delete__方法的對象。
單看定義,還是比較抽象的。talk is cheap??创a吧:
class WebFramework(object): def __init__(self, name='Flask'): self.name = name def __get__(self, instance, owner): return self.name def __set__(self, instance, value): self.name = value class PythonSite(object): webframework = WebFramework() In [1]: PythonSite.webframework Out[1]: 'Flask' In [2]: PythonSite.webframework = 'Tornado' In [3]: PythonSite.webframework Out[3]: 'Tornado'
定義了一個類WebFramework,它實(shí)現(xiàn)了描述符協(xié)議__get__和__set__,該對象(類也是對象,一切都是對象)即成為了一個描述器。同時(shí)實(shí)現(xiàn)__get__和__set__的稱之為資料描述器(data descriptor)。僅僅實(shí)現(xiàn)__get__的則為非描述器。兩者的差別是相對于實(shí)例的字典的優(yōu)先級。
如果實(shí)例字典中有與描述器同名的屬性,如果描述器是資料描述器,優(yōu)先使用資料描述器,如果是非資料描述器,優(yōu)先使用字典中的屬性。
描述器的調(diào)用
對于這類魔法,其調(diào)用方法往往不是直接使用的。例如裝飾器需要用 @ 符號調(diào)用。迭代器通常在迭代過程,或者使用 next 方法調(diào)用。描述器則比較簡單,對象屬性的時(shí)候會調(diào)用。
In [15]: webframework = WebFramework() In [16]: webframework.__get__(webframework, WebFramework) Out[16]: 'Flask'
描述器的應(yīng)用
描述器的作用主要在方法和屬性的定義上。既然我們可以重新描述類的屬性,那么這個魔法就可以改變類的一些行為。最簡單的應(yīng)用則是可以配合裝飾器,寫一個類屬性的緩存。Flask的作者寫了一個werkzeug網(wǎng)絡(luò)工具庫,里面就使用描述器的特性,實(shí)現(xiàn)了一個緩存器。
class _Missing(object): def __repr__(self): return 'no value' def __reduce__(self): return '_missing' _missing = _Missing() class cached_property(object): def __init__(self, func, name=None, doc=None): self.__name__ = name or func.__name__ self.__module__ = func.__module__ self.__doc__ = doc or func.__doc__ self.func = func def __get__(self, obj, type=None): if obj is None: return self value = obj.__dict__.get(self.__name__, _missing) if value is _missing: value = self.func(obj) obj.__dict__[self.__name__] = value return value class Foo(object): @cached_property def foo(self): print 'first calculate' result = 'this is result' return result f = Foo() print f.foo # first calculate this is result print f.foo # this is result
運(yùn)行結(jié)果可見,first calculate只在第一次調(diào)用時(shí)候被計(jì)算之后就把結(jié)果緩存起來了。這樣的好處是在網(wǎng)絡(luò)編程中,對HTTP協(xié)議的解析,通常會把HTTP的header解析成python的一個字典,而在視圖函數(shù)的時(shí)候,可能不知一次的訪問這個header,因此把這個header使用描述器緩存起來,可以減少多余的解析。
描述器在python的應(yīng)用十分廣泛,通常是配合裝飾器一起使用。強(qiáng)大的魔法來自強(qiáng)大的責(zé)任。描述器還可以用來實(shí)現(xiàn)ORM中對sql語句的"預(yù)編譯"。恰當(dāng)?shù)氖褂妹枋銎?,可以讓自己的Python代碼更優(yōu)雅。
相關(guān)文章
python實(shí)現(xiàn)簡單飛機(jī)大戰(zhàn)小游戲
這篇文章主要為大家詳細(xì)介紹了python實(shí)現(xiàn)簡單飛機(jī)大戰(zhàn)小游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-05-05Python實(shí)現(xiàn)進(jìn)程同步和通信的方法
本篇文章主要介紹了Python實(shí)現(xiàn)進(jìn)程同步和通信的方法,詳細(xì)的介紹了Process、Queue、Pipe、Lock等組件,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-01-01Ubuntu權(quán)限不足無法創(chuàng)建文件夾解決方案
這篇文章主要介紹了Ubuntu權(quán)限不足無法創(chuàng)建文件夾解決方案,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-11-11Python可變參數(shù)*args和**kwargs用法實(shí)例小結(jié)
這篇文章主要介紹了Python可變參數(shù)*args和**kwargs用法,結(jié)合實(shí)例形式總結(jié)分析了Python中可變參數(shù)*args和**kwargs的功能、區(qū)別與具體使用技巧,需要的朋友可以參考下2018-04-04