面向對象之魔術方法

特殊屬性

屬性

含義

__name__

類、函數、方法的名稱

__module__

類定義所在的模塊名

__class__

對象或類所屬的類

__bases__

類的基類的元組,順序為它們在基類列表中出現的順序

__doc__

類、函數的文檔字符串,若沒定義則為None

__mro__

類的mro,方法查找順序

__dict__

類或實例的屬性,可寫的字典

查看屬性

__dir__:返回類或者對象的所有成員名稱列表,dir()即調用__dir__(),若提供__dir__(),則返回屬性的列表,否則會盡量從__dict__中收集多的信息

若dir([obj])參數obj包含__dir__()方法,該方法被調用。若參數obj不包含__dir__()方法,則將會收集盡量多的參數信息

對不同類型具有不同行為

若對象為模塊對象,返回的列表包含模塊的屬性名

若對象為類型或類對象,返回的列表包含類的屬性名、基類的屬性名

否則,返回列表包含對象的屬性名、類的屬性名、類的基類的屬性名

?
?

魔術方法

分類

創建、初始化、銷毀

__init__、__del__

hash

bool

可視化

運算符重載

容器和大小

可調用對象

上下文管理

反射

描述器

其他

hash

hash的特點

固定大小

雪崩效應

單向不可逆

__hash__:內建函數hash()調用的返回值,返回一個整數,若定義該方法則該類的實例就可hash

__eq__:對應==,判斷兩個對象是否相等,返回bool值

__hash__僅返回一個hash值作為set或dict的key,但去重需要__eq__來判斷2個對象是否相等

hash值相等只是hash沖突,不能說明兩個對象相等

不可hash對象isinstan(obj,collections.Hashable) = False

__hash__ = None:設置類不能被hash

?
?

bool

__bool__:內建函數bool(),或者對象放在邏輯表達式的位置,調用該函數返回bool值,沒定義__bool__()就找__len__()返回長度,長度非0為真,若__len__()也沒有定義,則所有實例均返回真

?
?

可視化

__repr__:內建函數repr()對一個對象獲取字符串表達。調用__repr__方法返回字符串表達,若__repr__沒有定義,就直接返回object的內存地址信息

__str__:str()函數、內建函數format()、print()調用,需要返回對象的字符串表達。若未定義則調用__repr__返回字符串表達,__repr__未定義返回object的內存地址信息

__bytes__:bytes()函數調用,返回一個對象的bytes表達

?
?

運算符重載

<,<=,==>,>=!=

__lt__,__le____eq__,__gt__,__ge____ne__

+,-,*,/,%,//,**,divmod

__add__,__sub__,__mul__,__trudiv__,__mod__,__floordiv____pow__,__divmod__

+=,-=,*=,/=,%=,//=,**=

__iadd____isub__,__imul__,__itrudiv____imod__,__ifloordiv__,__ipow__

@functools.total_ordering裝飾器

__lt____le__,__eq__,__gt____ge__是比較大小必須實現的方法,但是全寫太麻煩,使用該裝飾器可簡化代碼

要求__eq__必須實現,剩余其他方法實現其一即可

缺點:引入了不需要的方法,影響性能

自己實現只需保證__eq__,__lt____gt__,__le____ge__五選三實現即可

容器

__len__:內建函數len(),返回對象的長度,若將對象當做容器類看,bool()函數調用時,若沒有__bool__()方法,則看__len__()是否存在,存在返回非0

__iter__:迭代容器時調用,返回一個新的迭代器對象

__contains__:in成員運算符,若未實現就調用__iter__方法遍歷

__getitem__:實現self[key]訪問。序列對象,key接受整數為索引或切片,對于set或dict,key為hashable,可以不存在KeyError異常

__setitem__:設置值

__missing__:字典或其子類使用__getitem__()調用時,key不存在執行該方法

可調用對象

__call__:類中定義一個該方法,實例就可像函數一樣調用

?
?

上下文管理

當一個對象同時實現了__enter__()和__exit__()方法,它就屬于上下文管理的對象

__enter__:進入與此對象相關的上下文,若存在該方法,with語法會將該方法的返回值綁定到as字句中指定的變量上

__exit__():退出與此對象相關的上下文

實例化對象時不會調用__enter__,進入with語句塊調用__enter__方法 –》執行語句體 –》離開with語句塊調用__exit__()方法

安全性

存在異常,enter和exit照樣執行,上下文管理是安全的

方法的參數

__enter__方法沒有參數

__exit__方法有3個參數,與異常相關,沒有異常則3個參數均為None

exc_type,異常類型

exc_value,異常的值

traceback,異常的追蹤信息

__exit__方法返回一個等效True的值,可以壓制異常,否則繼續拋出異常

應用場景

增強功能

在代碼執行的前后增加代碼,以增強其功能,類似裝飾器

資源管理

打開文件需要關閉

權限驗證

在執行代碼前做權限的驗證

contextlib.contextmanager

裝飾器,實現上下文管理,裝飾一個函數,而不用像類一樣實現__enter__()和__exit__()方法

對下面的函數有要求,必須有yield,必須返回一個生成器,且只有一個yield值

該裝飾器接收一個生成器對象作為參數

?
?

若業務邏輯簡單可使用contextlib.contextmanager,若復雜,用類增加__enter__()和__exit__()方法更方便

反射

概述

運行時,區別于編譯時,指的是程序被加載到內存中執行的時候

反射,reflection,指的是運行時獲取類型定義信息

在Python中,能通過一個對象,找出其type、class、attribute或method的能力,稱為反射或自省

具有反射能力的函數:type()、isinstance()、callable()、dir()、getattr()

相關函數及方法

面向對象之魔術方法

通過屬性字典__dict__可以訪問對象的屬性,本質上就是利用反射的能力

內建函數

意義

getattr(object, name[, default]) -> value

通過name返回object的屬性值,當屬性不存在返回default,若無default則拋出AttributeError,name必須為字符串

setattr(obj, name, value)

object的屬性存在則覆蓋,不存在則新增

hasattr(obj, name)

判斷對象是否有該屬性,name必須為字符串

?
?

面向對象之魔術方法

這種動態增刪屬性的方式是運行時改變類或實例的方式,但裝飾器或Mixin在定義時就寫定了,反射具有更大的靈活性

反射相關魔術方法

__getattr__():一個類的屬性會按照繼承關系查找屬性,若找不到,就會執行__getattr__()方法,如果沒有該方法,則拋出AttributeError

面向對象之魔術方法

屬性查找順序:instance.__dict__ ——》 instance.__class__.__dict__ ——》繼承的祖先類(直到object)的__dict__ ——》找不到 ——》調用__getattr__()

__setattr__():實例通過.點設置屬性,如self.x = x就會調用__setattr__()。若屬性要加到實例自己的__dict__中,就需要自己完成

面向對象之魔術方法

__setattr__()方法可以攔截對實例屬性的增加、修改操作,若要設置生效,就需要自己操作實例的__dict__

面向對象之魔術方法

__delattr__():可以阻止通過實例刪除屬性的操作,但通過類依然可以刪除屬性

面向對象之魔術方法

__getattribute__:實例的所有屬性訪問,都會第一個調用__getattribute__方法,它阻止了屬性的查找,該方法應該返回一個值(計算后的)或拋出一個AttributeError異常

該方法的return值將作為屬性查找的結果。如果拋出AttributeError,則會直接調用__getattr__方法,表示屬性沒有找到

__getattribute__方法中為了避免該方法出現無限遞歸,其實現應該永遠調用基類的同名方法以訪問需要的任何屬性

面向對象之魔術方法

魔術方法

意義

__getattr__()

當通過搜索實例、實例的類及祖先類查不到屬性時,就會調用該方法

__setattr__()

通過.訪問實例屬性,進行增加、修改

__delattr__()

當通過實例來刪除屬性時調用此方法

__getattribute__()

實例的所有屬性調用都從此方法開始

屬性查找順序:實例調用__getattribute__() ——》instance.__dict__——》instance.__class__.__dict__ ——》繼承的祖先類(直到object)的__dict__ ——》調用__getattr__()

描述器

class A含有__get__、__set__、__delete__方法中的任意一個,class B的類屬性x為class A的實例,對class B或B的實例的x屬性的讀取,成為對class A的實例的訪問,就會調用class A中的方法,只有類屬性是class A的實例才會調用class A中的方法

描述器的表現

3個魔術方法:__get__()、__set__()、__delete__()

方法簽名

object.__get__(self,instance,owner)

object.__set__(self,instance,value)

object.__delete__(self,instance)

其中,self指代當前實例,調用者;instance是owner的實例;owner是屬性所屬的類

描述器定義

一個類實現了__get__、__set__、__delete__三個方法中的任何一個,就是描述器

若僅實現__get__,即為非數據描述器non-data descriptor

同時實現__get__、__set__就是數據描述器data descriptor

若一個類的類屬性設置為描述器,則它被稱為owner屬主

屬性的訪問順序

數據描述器 ——》實例的__dict__ ——》非數據描述器

本質:若類屬性指代的是數據描述器,則實例中和類屬性同名的屬性將從__dict__中被刪除,造成數據描述器優先訪問的假象

??

原創文章,作者:ZBD20,如若轉載,請注明出處:http://www.www58058.com/99067

(0)
ZBD20ZBD20
上一篇 2018-05-20
下一篇 2018-05-21

相關推薦

  • Python第二周小結

    不知不覺已經正式學習接觸Python兩周了,第二周主要開始了Python內置數據結構的學習,包括從一開始的列表list,元組tuple,字符串string,再到后來的bytes, bytearray, 以及最后的集合set。這些數據結構可以說Python最為基礎的幾種類型,想要用Python寫出漂亮的代碼離不開對他們的熟練掌握與深刻理解。這幾個結構各有各的特…

    Python筆記 2018-03-31
  • Python學習第十三周總結

    網絡協議和管理、http服務和Apache

    2018-06-03
  • Linux介紹

    Linux介紹 Linux概述 Linux概述 Linux內核由芬蘭人Linus Torvalds 1991年根據386架構開發。Linux是系統的內核并非系統,之后的RED HALT 、Centos等都是以Linux為內核的類UNIX操作系統。 1969年UNIX系統由THOMPSON和D.M.Riche在美國貝爾實驗室開發 1990年芬蘭人Linus T…

    Python筆記 2018-03-26
  • Python函數

    函數 數學函數 Python函數 若干語句塊、函數名稱、參數列表構成,組織代碼的最小單元 完成一定的功能 作用 結構化編程對代碼的最基本的封裝,一般按照功能組織一段代碼 復用,減少冗余代碼 簡潔美觀,可讀易懂 函數分類 內建函數,max()、reversed() 庫函數,math.ceil() 函數定義、調用 def語句定義函數 def 函數名(參數列表):…

    2018-04-16
  • Python內置數據結構

    解析器和生成器

    Python筆記 2018-04-08
欧美性久久久久