什么是上下文管理器
官方解釋
上下文管理器是一個對象它定義了在執行 with 語句時要建立的運行時上下文上下文管理器處理進入和退出所需的運行時上下文以執行代碼塊上下文管理器通常使用 with 語句調用,但也可以通過直接調用它們的實例方法來使用
一頓花里胡哨猛如虎,結果我也不太懂
簡單一句話
同時包含 __enter__() 和 __exit__() 方法的對象就是上下文管理器
__enter__(self)
進入上下文管理器自動調用的方法
該方法會在 with ... as ... 代碼塊執行之前執行
如果 with 語句有 as 子句,且該方法有返回值,那么該方法的返回值會被賦值給 as 子句后的變量,最常見的 with open('file_path', 'w') as file:
該方法可以返回多個值,因此在 as 子句后面也可以指定多個變量(多個變量必須由“()”括起來組成元組)
__exit__(self, exc_type, exc_value, exc_traceback)
退出上下文管理器自動調用的方法,會返回一個布爾類型的值
該方法會在 with ... as ... 代碼塊執行之后執行
如果 with ... as ... 代碼塊成功執行結束,程序自動調用該方法,且三個參數都為 None
如果 with ... as ... 代碼塊執行時發生異常,通過 sys.exc_info() 得到異常信息,三個參數值分別是:異常類型、異常信息、異?;厮菪畔㈩愋?/p>
有哪些常見上下文管理器?
打開文件
1
2
|
with open ( 'file_path' , 'w' ) as file : file .write( 'hello world !' ) |
拆分了解
上下文表達式: with open('file_path', 'w') as file:
上下文管理器: open('file_path', 'w')
file:可以理解為資源對象
執行順序
先執行 open() 的 __enter__() 方法,將返回值賦值給 file
執行 file.write('hello world !')
最后執行 open() 的 __exit__() 方法
自定義上下文管理器
其實有兩種方式
基于類實現上下文管理器
只需要給對象添加一個 __enter__ 和一個 __exit__ 方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
import sys class Resource: def __init__( self , name): self .name = name print ( "== 初始化方法 ==" ) def __enter__( self ): print (f "** 進入上下文管理器自動調用:name is {self.name}" ) # 可以返回任意類型的值 return { "name" : self .name} def __exit__( self , exc_type, exc_val, exc_tb): print (f "## 退出上下文管理器自動調用:" , sys.exc_info(), exc_type, exc_val, exc_tb) if exc_tb is None : print ( "沒有異常時關閉資源" ) else : print ( "遇到異常時關閉資源" ) |
通過 with 來調用該上下文管理器
也稱為:使用 with ... as ... 管理資源
1
2
|
with Resource( "小菠蘿" ) as r: print (r) |
console 輸出結果
== 初始化方法 ==
** 進入上下文管理器自動調用:name is 小菠蘿
{'name': '小菠蘿'}
## 退出上下文管理器自動調用: (None, None, None) None None None
沒有異常時關閉資源
__exit__() 方法的三個參數值都是 None
with 代碼塊拋出異常
1
2
3
4
|
with Resource( "異常小菠蘿" ) as r: print ( '[with代碼塊] 異常之前的代碼' ) raise Exception( "拋出了 Exception" ) print ( '[with代碼塊] ~~~~~~~~異常之后的代碼' ) |
console 輸出結果
== 初始化方法 ==
** 進入上下文管理器自動調用:name is 異常小菠蘿
[with代碼塊] 異常之前的代碼
## 退出上下文管理器自動調用: (<class 'Exception'>, Exception('拋出了 Exception'), <traceback object at 0x10e203200>) <class 'Exception'> 拋出了 Exception <traceback object at 0x10e203200>
遇到異常時關閉資源
Traceback (most recent call last):
File "/Users/polo/Documents/pylearn/第七章:文件相關/1_上下文管理器.py", line 36, in <module>
raise Exception("拋出了 Exception")
Exception: 拋出了 Exception
代碼塊拋出異常的時候,可以看到 __exit__() 方法的三個參數值的確來源于 sys.exc_info()
總結
- 無論 with 代碼塊是否有異常,最終都會自動調用 __exit__() 方法
- 當拋出異常時,__exit__() 默認返回 None,會重新拋出異常到外面,讓 with ... as ... 以外的代碼來處理異常
- 反之,如果返回 True,就會忽略異常,不再對異常進行處理
__exit__() 返回 True
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
def __exit__( self , exc_type, exc_val, exc_tb): print (f "## 退出上下文管理器自動調用:" , sys.exc_info(), exc_type, exc_val, exc_tb) if exc_tb is None : print ( "沒有異常時關閉資源" ) else : print ( "遇到異常時關閉資源" ) return True # 再次運行 with Resource( "異常小菠蘿" ) as r: print ( '[with代碼塊] 拋出異常之前的代碼' ) raise Exception print ( '[with代碼塊] 拋出異常之后的代碼' ) |
console 輸出結果
== 初始化方法 ==
** 進入上下文管理器自動調用:name is 異常小菠蘿
[with代碼塊] 異常之前的代碼
## 退出上下文管理器自動調用: (<class 'Exception'>, Exception('拋出了 Exception'), <traceback object at 0x100e29200>) <class 'Exception'> 拋出了 Exception <traceback object at 0x100e29200>
遇到異常時關閉資源
不再拋出異常
基于生成器實現上下文管理器
通過裝飾器 contextlib.contextmanager,來定義自己所需的基于生成器的上下文管理器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
from contextlib import contextmanager @contextmanager def file_manager(name, mode): try : # 1、打開文件 file = open (name, mode) # 2、返回文件資源對象 yield file finally : # 3、關閉文件 file .close() with file_manager( 'a.txt' , 'w' ) as file : print ( file ) file .write( 'hello world' ) |
函數 file_manager() 就是一個生成器
當執行 with as 語句時,獲取文件資源對象,生成器暫停執行,返回文件資源對象并賦值給 file
當 with 語句執行完后,生成器繼續執行剩余代碼,關閉文件,釋放資源
總結
- 基于生成器的上下文管理器時,不再用定義 __enter__() 和 __exit__() 方法
- 但需要加上裝飾器 @contextmanager
with 語句的教程
http://m.ythuaji.com.cn/article/220256.html
以上就是Python編程ContextManager上下文管理器講解的詳細內容,更多關于Python編程Context Manager的資料請關注服務器之家其它相關文章!
原文鏈接:https://blog.csdn.net/qq_33801641/article/details/120500590