目錄:
一、構(gòu)造和初始化
二、屬性訪問控制
三、描述符協(xié)議
四、自定義容器(Container)
五、上下文管理器
六、可調(diào)用對象(__call__方法)
Python魔法方法(魔術(shù)方法)
在Python中,所有以雙下劃線包起來的方法,都統(tǒng)稱為"魔法方法"。
一、構(gòu)造和初始化
- __new__是在實例創(chuàng)建之前被調(diào)用的。因為它的任務就是創(chuàng)建實例然后返回該實例,是個靜態(tài)方法。
- __init__是在實例對象創(chuàng)建完成后被調(diào)用的。然后設(shè)置對象屬性的一些初始值。
二、屬性訪問控制
- __getattr__(self, name): 訪問不存在的屬性時調(diào)用。
- __getattribute__(self, name):訪問存在的屬性時調(diào)用(先調(diào)用該方法,查看是否存在該屬性,若不存在,接著去調(diào)用__getattr__)。
- __setattr__(self, name, value):設(shè)置實例對象的一個新的屬性時調(diào)用。
- __delattr__(self, name):刪除一個實例對象的屬性時調(diào)用 。
三、描述符協(xié)議
描述符是一個類,定義了訪問另一個類屬性的方式。提高屬性訪問控制代碼可復用性。
實現(xiàn)了__get__()、__set__()、__delete__() 其中至少一個方法的類,就是一個描述符:
- 實現(xiàn)了__get__()和__set__()的描述符稱為數(shù)據(jù)描述符。
- 只實現(xiàn)了__get__()的描述符稱為非數(shù)據(jù)描述符。
- __get__: 用于訪問屬性。它返回屬性的值,若屬性不存在、不合法等都可以拋出對應的異常。
- __set__:將在屬性分配操作中調(diào)用。不會返回任何內(nèi)容。
- __delete__:控制刪除操作。不會返回內(nèi)容。
四、自定義容器(Container)
在Python中,如果我們想實現(xiàn)創(chuàng)建類似于序列和映射的類(可以迭代以及通過[下標]返回元素),可以通過重寫魔法方法__getitem__、__setitem__、__delitem__、__len__方法去模擬。
- __getitem__(self,key):返回鍵對應的值。
- __setitem__(self,key,value):設(shè)置給定鍵的值。
- __delitem__(self,key):刪除給定鍵對應的元素。
- __len__():返回元素的數(shù)量。
五、上下文管理器
1.使用類
在一個類里,如果實現(xiàn)了__enter__和__exit__方法,這個類的實例就是一個上下文管理器。
在編寫代碼時,可以將資源的連接或者獲取放在__enter__中,而將資源的關(guān)閉寫在__exit__ 中。__enter__中需要返回當前實例對象。
上下文管理器的作用:
- 可以以一種更加優(yōu)雅的方式,操作(創(chuàng)建/獲取/釋放)資源,如文件操作、數(shù)據(jù)庫連接。
- 可以以一種更加優(yōu)雅的方式,處理異常。(處理異常通常都是使用 try...execept... 來捕獲處理的。這樣做一個不好的地方是,在代碼的主邏輯里,會有大量的異常處理代理,這會很大的影響我們的可讀性。)
- __enter__:進入方法。
- __exit__:退出方法。
class ContextManager:
def __enter__(self):
return self
def __exit__(self, exc_type, exc_val, exc_tb):
"""
:param exc_type: 異常類型
:param exc_val: 異常實例
:param exc_tb: 堆棧信息(traceback對象)
:return: 如果返回True則代表已經(jīng)正確處理異常。如果返回True以外其他值,則代表異常未處理,則將異常層層上報。
"""
return True
示例1:
class Resource:
def __enter__(self):
print('===connect to resource===')
return self
def __exit__(self, exc_type, exc_val, exc_tb):
print('===close resource connection===')
def operate(self):
print('===in operation===')
with Resource() as res:
res.operate()

運行結(jié)果1
2.使用contextlib
以yield為分界點:
- yield之前的代碼相當于__enter__中的代碼。
- yield之后的值相當于__enter__的返回值。
- yield之后的代碼相當于__exit__中的代碼。
import contextlib
@contextlib.contextmanager
def context_manager():
# __enter__方法
print('===connect to resource===')
try:
yield __enter__方法的返回值
except Exception:
print("拋出異常!")
# __exit__方法
print('===close resource connection===')
六、可調(diào)用對象(__call__方法)
所有的函數(shù)都是可調(diào)用對象。
一個類實例也可以變成一個可調(diào)用對象,只需要實現(xiàn)一個特殊方法__call__()。
示例:斐波那契數(shù)列
class Fib:
def __init__(self):
pass
def __call__(self, num):
a, b = 1, 1\_\_call\_\_方法
self.list = []
for i in range(num):
self.list.append(a)
a, b = b, a+b
return self.list
def __str__(self):
return str(self.list)
f = Fib()
print(f(10))

運行結(jié)果