很久都沒寫 Flask 程式碼相關了,想想也真是慚愧,然並卵,這次還是不寫 Flask 相關,不服你來打我啊(就這麼賤,有本事咬我啊
這次我來寫一下 Python 一個很重要的東西,也就是 Descriptor (描述子)
初識描述符
老規矩, Talk is cheap,Show me the code. 讓我們先來看一段程式碼
classPerson(object): """""" #---------------------------------------------------------------------- def__init__(self, first_name, last_name): """Constructor""" self.first_name = first_name self.last_name = last_name #---------------------------------------------------------------------- @property deffull_name(self): """ Return the full name """ return"%s %s"% (self.first_name, self.last_name) if__name__=="__main__": person = Person("Mike","Driscoll") print(person.full_name) # 'Mike Driscoll' print(person.first_name) # 'Mike'
這段代大家一定很熟悉,恩, property 嘛,誰不知道呢,但是 property 的實現機制大家清楚麼?什麼不清楚?那還學個毛的 Python 啊。 。 。開個玩笑,我們看下面一段程式碼
classProperty(object): "Emulate PyProperty_Type() in Objects/descrobject.c" def__init__(self, fget=None, fset=None, fdel=None, doc=None): self.fget = fget self.fset = fset self.fdel = fdel ifdocisNoneandfgetisnotNone: doc = fget.__doc__ self.__doc__ = doc def__get__(self, obj, objtype=None): ifobjisNone: returnself ifself.fgetisNone: raiseAttributeError("unreadable attribute") returnself.fget(obj) def__set__(self, obj, value): ifself.fsetisNone: raiseAttributeError("can't set attribute") self.fset(obj, value) def__delete__(self, obj): ifself.fdelisNone: raiseAttributeError("can't delete attribute") self.fdel(obj) defgetter(self, fget): returntype(self)(fget, self.fset, self.fdel, self.__doc__) defsetter(self, fset): returntype(self)(self.fget, fset, self.fdel, self.__doc__) defdeleter(self, fdel): returntype(self)(self.fget, self.fset, fdel, self.__doc__)
看起來是不是很複雜,沒事,我們來一步步的看。不過這裡我們先給一個結論: Descriptors 是一種特殊 的對象,這種對象實作了 __get__ , __set__ , __delete__ 這三個特殊方法。
詳解描述詞
說說 Property
在上文,我們給了 Propery 實作程式碼,現在讓我們來詳細說說這個
classPerson(object): """""" #---------------------------------------------------------------------- def__init__(self, first_name, last_name): """Constructor""" self.first_name = first_name self.last_name = last_name #---------------------------------------------------------------------- @property deffull_name(self): """ Return the full name """ return"%s %s"% (self.first_name, self.last_name) if__name__=="__main__": person = Person("Mike","Driscoll") print(person.full_name) # 'Mike Driscoll' print(person.first_name) # 'Mike'
首先,如果你對裝飾器不了解的話,你可能要去看看這篇文章,簡而言之,在我們正式運行程式碼之前,我們的解釋器就會對我們的程式碼進行一次掃描,對涉及裝飾器的部分進行替換。類裝飾器同理。在上文中,這段程式碼
@Property deffull_name(self): """ Return the full name """ return"%s %s"% (self.first_name, self.last_name)
會觸發這樣一個過程,即 full_name=Property(full_name) 。然後在我們後面實例化物件之後我們呼叫person.full_name 這樣一個過程其實等價於person.full_name.__get__(person) 然後進而觸發__get__() 方法裡所寫的return self.fget(obj) 即原本上我們所寫的def full_name 內的執行程式碼。
這時候,同志們可以去思考下 getter() , setter() ,以及 deleter() 的具體運作機制了=。 =如果還是有問題,歡迎在評論裡討論。
關於描述詞
還記得之前我們所提到的一個定義麼: Descriptors 是一種特殊的對象,這種對象實現了 __get__ , __set__ , __delete__ 這三個特殊方法 。然後在Python 官方文件的說明中,為了體現描述符的重要性,有這樣一段話:「They are the mechanism behind properties, methods, static methods, class methods, and super(). They are used throughout Python itself tomethods, and super(). They are used throughout Python itself to implement the new style classes introduced in version 2.2. 」 簡而言之就是先有描述子後有天,秒天秒地秒空氣。恩,在新式類別中,屬性,方法調用,靜態方法,類別方法等都是基於描述符的特定使用。
OK,你可能想問,為什麼描述詞這麼重要?別急,我們接著看
使用描述符
首先請看下一段程式碼
classA(object):#註:在Python 3.x 版本中,對於new class 的使用不需要明確的指定從object 類別進行繼承,如果在Python 2.X(x>2)的版本中則需要
defa(self): pass if__name__=="__main__": a=A() a.a()
大家都注意到我們存在著這樣一個語句 a.a() ,好的,現在請大家思考下,我們在呼叫這個方法的時候發生了什麼事?
OK?想出來了麼?沒有?好的我們繼續
首先我們呼叫一個屬性的時候,不管是成員還是方法,我們都會觸發這樣一個方法用於呼叫屬性__getattribute__() ,在我們的__getattribute__() 方法中,如果我們嘗試調用的屬性實現了我們的描述子協議,那麼會產生這樣一個呼叫過程type(a).__dict__['a'].__get__(b,type(b)) 。好的這裡我們又要給一個結論了:「在這樣一個呼叫過程中,有這樣一個優先順序,如果我們所嘗試呼叫屬性是一個data descriptors ,那麼不管這個屬性是否存在我們的實例的__dict__在字典中,優先呼叫我們描述子裡的__get__ 方法,如果我們所嘗試呼叫屬性是一個non data descriptors ,那麼我們優先呼叫我們實例裡的__dict__ 裡的存在的屬性,如果不存在,則依照對應原則往上尋找我們類,父類別中的__dict__ 中所包含的屬性,一旦屬性存在,則呼叫__get__ 方法,如果不存在則呼叫__getattr__() 方法」。理解起來有點抽象?沒事,我們馬上會講,不過在這裡,我們先解釋下 data descriptors 與 non data descriptors ,再來看一個例子。什麼是 data descriptors 與 non data descriptors 呢?其實很簡單,在描述符中同時實作了 __get__ 與 __set__ 協定的描述符是 data descriptors ,如果只實作了 __get__ 協定的則是 non data descriptors 。好了我們現在來看個例子:
importmath classlazyproperty: def__init__(self, func): self.func = func def__get__(self, instance, owner): ifinstanceisNone: returnself else: value = self.func(instance) setattr(instance, self.func.__name__, value) returnvalue classCircle: def__init__(self, radius): self.radius = radius pass @lazyproperty defarea(self): print("Com") returnmath.pi * self.radius *2 deftest(self): pass if__name__=='__main__': c=Circle(4) print(c.area)
好的,让我们仔细来看看这段代码,首先类描述符 @lazyproperty 的替换过程,前面已经说了,我们不在重复。接着,在我们第一次调用 c.area 的时候,我们首先查询实例 c 的 __dict__ 中是否存在着 area 描述符,然后发现在 c 中既不存在描述符,也不存在这样一个属性,接着我们向上查询 Circle 中的 __dict__ ,然后查找到名为 area 的属性,同时这是一个 non data descriptors ,由于我们的实例字典内并不存在 area 属性,那么我们便调用类字典中的 area 的 __get__ 方法,并在 __get__ 方法中通过调用 setattr 方法为实例字典注册属性 area 。紧接着,我们在后续调用 c.area 的时候,我们能在实例字典中找到 area 属性的存在,且类字典中的 area 是一个 non data descriptors ,于是我们不会触发代码里所实现的 __get__ 方法,而是直接从实例的字典中直接获取属性值。
描述符的使用
描述符的使用面很广,不过其主要的目的在于让我们的调用过程变得可控。因此我们在一些需要对我们调用过程实行精细控制的时候,使用描述符,比如我们之前提到的这个例子
classlazyproperty: def__init__(self, func): self.func = func def__get__(self, instance, owner): ifinstanceisNone: returnself else: value = self.func(instance) setattr(instance, self.func.__name__, value) returnvalue def__set__(self, instance, value=0): pass importmath classCircle: def__init__(self, radius): self.radius = radius pass @lazyproperty defarea(self, value=0): print("Com") ifvalue ==0andself.radius ==0: raiseTypeError("Something went wring") returnmath.pi * value *2ifvalue !=0elsemath.pi * self.radius *2 deftest(self): pass
利用描述符的特性实现懒加载,再比如,我们可以控制属性赋值的值
classProperty(object): "Emulate PyProperty_Type() in Objects/descrobject.c" def__init__(self, fget=None, fset=None, fdel=None, doc=None): self.fget = fget self.fset = fset self.fdel = fdel ifdocisNoneandfgetisnotNone: doc = fget.__doc__ self.__doc__ = doc def__get__(self, obj, objtype=None): ifobjisNone: returnself ifself.fgetisNone: raiseAttributeError("unreadable attribute") returnself.fget(obj) def__set__(self, obj, value=None): ifvalueisNone: raiseTypeError("You can`t to set value as None") ifself.fsetisNone: raiseAttributeError("can't set attribute") self.fset(obj, value) def__delete__(self, obj): ifself.fdelisNone: raiseAttributeError("can't delete attribute") self.fdel(obj) defgetter(self, fget): returntype(self)(fget, self.fset, self.fdel, self.__doc__) defsetter(self, fset): returntype(self)(self.fget, fset, self.fdel, self.__doc__) defdeleter(self, fdel): returntype(self)(self.fget, self.fset, fdel, self.__doc__) classtest(): def__init__(self, value): self.value = value @Property defValue(self): returnself.value @Value.setter deftest(self, x): self.value = x
如上面的例子所描述的一样,我们可以判断所传入的值是否有效等等。

本篇文章给大家带来了关于Python的相关知识,其中主要介绍了关于Seaborn的相关问题,包括了数据可视化处理的散点图、折线图、条形图等等内容,下面一起来看一下,希望对大家有帮助。

本篇文章给大家带来了关于Python的相关知识,其中主要介绍了关于进程池与进程锁的相关问题,包括进程池的创建模块,进程池函数等等内容,下面一起来看一下,希望对大家有帮助。

本篇文章给大家带来了关于Python的相关知识,其中主要介绍了关于简历筛选的相关问题,包括了定义 ReadDoc 类用以读取 word 文件以及定义 search_word 函数用以筛选的相关内容,下面一起来看一下,希望对大家有帮助。

VS Code的确是一款非常热门、有强大用户基础的一款开发工具。本文给大家介绍一下10款高效、好用的插件,能够让原本单薄的VS Code如虎添翼,开发效率顿时提升到一个新的阶段。

pythn的中文意思是巨蟒、蟒蛇。1989年圣诞节期间,Guido van Rossum在家闲的没事干,为了跟朋友庆祝圣诞节,决定发明一种全新的脚本语言。他很喜欢一个肥皂剧叫Monty Python,所以便把这门语言叫做python。

本篇文章给大家带来了关于Python的相关知识,其中主要介绍了关于数据类型之字符串、数字的相关问题,下面一起来看一下,希望对大家有帮助。

本篇文章给大家带来了关于Python的相关知识,其中主要介绍了关于numpy模块的相关问题,Numpy是Numerical Python extensions的缩写,字面意思是Python数值计算扩展,下面一起来看一下,希望对大家有帮助。


熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

AI Hentai Generator
免費產生 AI 無盡。

熱門文章

熱工具

mPDF
mPDF是一個PHP庫,可以從UTF-8編碼的HTML產生PDF檔案。原作者Ian Back編寫mPDF以從他的網站上「即時」輸出PDF文件,並處理不同的語言。與原始腳本如HTML2FPDF相比,它的速度較慢,並且在使用Unicode字體時產生的檔案較大,但支援CSS樣式等,並進行了大量增強。支援幾乎所有語言,包括RTL(阿拉伯語和希伯來語)和CJK(中日韓)。支援嵌套的區塊級元素(如P、DIV),

SublimeText3 Linux新版
SublimeText3 Linux最新版

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

DVWA
Damn Vulnerable Web App (DVWA) 是一個PHP/MySQL的Web應用程序,非常容易受到攻擊。它的主要目標是成為安全專業人員在合法環境中測試自己的技能和工具的輔助工具,幫助Web開發人員更好地理解保護網路應用程式的過程,並幫助教師/學生在課堂環境中教授/學習Web應用程式安全性。 DVWA的目標是透過簡單直接的介面練習一些最常見的Web漏洞,難度各不相同。請注意,該軟體中

PhpStorm Mac 版本
最新(2018.2.1 )專業的PHP整合開發工具