魔術方法 上下文管理

2021-09-23 15:29:34 字數 4216 閱讀 2413

檔案io操作可以對檔案物件使用上下文管理,使用with…as語法

上下文管理物件

方法意義

__enter__

進入與此物件相關的上下文.如果存在該方法,with語法會把該方法的返回值作為繫結到as子句中指定的變數上

__exit__

退出與此物件相關的上下文

例項化物件的時候,並不會呼叫enter,進入with語句塊呼叫__enter__方法,然後執行語句體,最後離開with語句塊的時候,呼叫__exit__方法

with可以開啟乙個上下文執行環境,在執行前做一些準備工作,執行後做一些收尾工作

注意,with並不開啟乙個新的作用域

上下文管理的安全性

class point:

def __init__(self):

print('init')

def __enter__(self):

print("enter")

def __exit__(self,exc_type,exc_val,exc_tb):

print('exit')

f = point()

with f as p:

import sys

sys.exit(1)

print(f==p)

從執行結果來看,依然執行__exit__函式,哪怕是退出python執行環境

說明上下文管理很安全

class point:

def __init__(self):

print('init')

def __enter__(self):

print("enter")

def __exit__(self,exc_type,exc_val,exc_tb):

print('exit')

#return 1 #壓制異常

p = open('t1.py')

with p as f:

print(f)

print(p)

print(f is p) #true

print(f == p) #true

f = point()

with f as p:

print(f==p) #flase

問題在__enter__方法上,它將自己的返回值賦給f,修改上例

with語法,會呼叫with後的物件__enter__方法,如果有as,則將該方法的返回值賦給as子句的變數

上例,可以等價為f = p.__enter__()

方法的引數

enter,沒有其他引數

exit,方法有三個引數(self,exc_type,exc_val,exc_tb)

這三個引數都與異常有關

如果該上下文退出時沒有異常,這三個引數都為none

如果有異常,引數意義如下

exc_type,異常型別

exc_val,異常的值

exc_tb(traceback),異常的追蹤資訊

__exit__方法返回乙個等效true的值,則壓制異常;否則,繼續丟擲異常

練習為加法函式計時

使用裝飾器顯示該函式的執行時長

使用上下文管理來顯示該函式的執行時長

import datetime

import time

def lagger(fn):

@wraps(fn)

def warrapr(*args,**kwargs):

statr = datetime.datetime.now()

ret = fn(*args,**kwargs)

datel = '{}s'.format((datetime.datetime.now()-statr).total_seconds())

print(datel)

return ret

return warrapr

@lagger

def add(x,y):

"""12312"""

time.sleep(2)

return x+y

print(add(10,10))

class point:

"""abddadss"""

def __init__(self,fn):

self.fn = fn

# self.__name__ = fn.__name__

# self.__doc__ = fn.__doc__

def __enter__(self):

self.start = datetime.datetime.now()

return self.fn

def __exit__(self, exc_type, exc_val, exc_tb):

delta = (datetime.datetime.now()-self.start).total_seconds()

print('{}s'.format(delta))

with point(add) as f:

print(add(4,5))

用類當字串

import datetime

import time

class point:

"""abddadss"""

def __init__(self,fn):

self.fn = fn

# self.__name__ = fn.__name__

# self.__doc__ = fn.__doc__

def __enter__(self):

self.start = datetime.datetime.now()

return self.fn

def __exit__(self, exc_type, exc_val, exc_tb):

delta = (datetime.datetime.now()-self.start).total_seconds()

# print(delta)

# print(exc_tb)

# print(exc_type)

# print(exc_val)

# print("~~~~~~~~~~~")

def __call__(self, *args, **kwargs):

statr = datetime.datetime.now()

ret = self.fn(*args,**kwargs)

datel = (datetime.datetime.now()-statr).total_seconds()

print(datel)

return ret

@point

def add(x,y):

"""12312"""

time.sleep(2)

return x+y

print(add(10,10))

上面的類可以用在上下文管理,也可以用作字串

1.增強功能

在**執行的前後增加**,以增強其功能.類似裝飾器的功能

2.資源管理

開啟了資源需要關閉,例如檔案物件 網路連線 資料庫連線等

3.許可權驗證

在執行**之前,做許可權的驗證,在__enter__中處理

contextlib.contextmanager

它是乙個裝飾器實現上下文管理,裝飾乙個函式,而不用像類一樣實現__enter__和__exit__方法

對下面的函式有要求:必須有yield,也就是這個函式必須返回乙個生成器,且只有yield乙個值

也就是說這個裝飾器接收乙個生成器物件作為引數

import contextlib

@contextlib.contextmanager

def foo():

print('abc')

try:

yield

finally:

print('123')

with foo() as f:

raise exception()

print(f)

f接收yield語句的返回值

增加異常

增加try finally

當yield發生處為生成器函式增加了上下文管理.這是為函式增加上下文機制的方式

魔術方法之上下文管理

檔案io操作可以對檔案物件使用上下文管理,使用with as語法。with open test as f pass仿照上例寫乙個自己的類,實現上下文管理 classa pass with a as f attributeerror enter pass提示屬性錯誤,沒有 enter 看來需要這個類屬...

Python魔術方法之上下文管理

魔術方法 上下文管理 檔案io操作可以對檔案物件使用上下文管理,使用with as語法 with open test as f pass 仿照上例寫乙個自己的類 提示錯誤 上下文管理物件 方法意義 enter進入與此物件相關的上下文,如果存在該方法,with語法會把該方法的返回值作為繫結到as子句中...

python的魔術方法之上下文管理

方法意義 enter 進入與此物件相關的上下文。如果存在該方法,with語法會把該方法的返回值作為繫結到as子句中指定的變數上 exit 退出與此物件相關的上下文。import time class point def init self print 1 init time.sleep 1 prin...