網(wǎng)站首頁(yè) 編程語(yǔ)言 正文
如果你有閱讀源碼的習(xí)慣,可能會(huì)看到一些優(yōu)秀的代碼經(jīng)常出現(xiàn)帶有 with
關(guān)鍵字的語(yǔ)句,它通常用在什么場(chǎng)景呢?對(duì)于系統(tǒng)資源如文件、數(shù)據(jù)庫(kù)連接、socket 而言,應(yīng)用程序打開(kāi)這些資源并執(zhí)行完業(yè)務(wù)邏輯之后,必須做的一件事就是要關(guān)閉(斷開(kāi))該資源。
比如 Python 程序打開(kāi)一個(gè)文件,往文件中寫(xiě)內(nèi)容,寫(xiě)完之后,就要關(guān)閉該文件,否則會(huì)出現(xiàn)什么情況呢?極端情況下會(huì)出現(xiàn) Too many open files
的錯(cuò)誤,因?yàn)橄到y(tǒng)允許你打開(kāi)的最大文件數(shù)量是有限的。同樣,對(duì)于數(shù)據(jù)庫(kù),如果連接數(shù)過(guò)多而沒(méi)有及時(shí)關(guān)閉的話(huà),就可能會(huì)出現(xiàn) Can not connect to MySQL server Too many connections
,因?yàn)閿?shù)據(jù)庫(kù)連接是一種非常昂貴的資源,不可能無(wú)限制的被創(chuàng)建。
一、with語(yǔ)句的使用
向文件中寫(xiě)入數(shù)據(jù)的示例代碼(基礎(chǔ)):
# -*- coding: utf-8 -*- # @Time : 2022-10-18 10:25 # @Author : AmoXiang # @File : demo1.py # @Software: PyCharm # @Blog : https://blog.csdn.net/xw1680 # 1、以寫(xiě)的方式打開(kāi)文件 f = open("1.txt", "w", encoding="utf8") # 2、寫(xiě)入文件內(nèi)容 f.write("hello world") # 3、關(guān)閉文件 f.close()
代碼說(shuō)明如下:文件使用完后必須關(guān)閉,因?yàn)槲募?duì)象會(huì)占用操作系統(tǒng)的資源,并且操作系統(tǒng)同一時(shí)間能打開(kāi)的文件數(shù)量也是有限的。這種寫(xiě)法可能出現(xiàn)一定的安全隱患,錯(cuò)誤代碼如下:
# -*- coding: utf-8 -*- # @Time : 2022-10-18 10:25 # @Author : AmoXiang # @File : demo1.py # @Software: PyCharm # @Blog : https://blog.csdn.net/xw1680 # 1、以寫(xiě)的方式打開(kāi)文件 f = open("1.txt", "r", encoding="utf8") # 2、寫(xiě)入文件內(nèi)容 f.write("hello world") # 3、關(guān)閉文件 f.close()
運(yùn)行結(jié)果如下圖所示:
代碼說(shuō)明:由于文件讀寫(xiě)時(shí)都有可能產(chǎn)生 IOError
,一旦出錯(cuò),后面的 f.close()
就不會(huì)調(diào)用。為了保證無(wú)論是否出錯(cuò)都能正確地關(guān)閉文件,我們可以使用 try ... finally
來(lái)解決。安全寫(xiě)法, 代碼如下:
# -*- coding: utf-8 -*- # @Time : 2022-10-18 10:32 # @Author : AmoXiang # @File : demo2.py # @Software: PyCharm # @Blog : https://blog.csdn.net/xw1680 try: # 1、以讀的方式打開(kāi)文件 f = open("1.txt", "r") # 2、讀取文件內(nèi)容 f.write("xxxxx") except IOError as e: print("文件操作出錯(cuò)", e) finally: # 3、關(guān)閉文件 f.close()
運(yùn)行結(jié)果:
文件操作出錯(cuò) not writable
這種方法雖然代碼運(yùn)行良好,但是缺點(diǎn)就是代碼過(guò)于冗長(zhǎng),并且需要添加 try-except-finally
語(yǔ)句,不是很方便,也容易忘記。在這種情況下,Python 提供了 with 語(yǔ)句的這種寫(xiě)法,既簡(jiǎn)單又安全,并且 with 語(yǔ)句執(zhí)行完成以后自動(dòng)調(diào)用關(guān)閉文件操作,即使出現(xiàn)異常也會(huì)自動(dòng)調(diào)用關(guān)閉文件操作。with 語(yǔ)句的示例代碼:
# -*- coding: utf-8 -*- # @Time : 2022-10-18 10:34 # @Author : AmoXiang # @File : demo3.py # @Software: PyCharm # @Blog : https://blog.csdn.net/xw1680 # 1、以寫(xiě)的方式打開(kāi)文件 with open("1.txt", "w") as f: # 2、讀取文件內(nèi)容 f.write("hello world") f.read() # 即使報(bào)錯(cuò),文件資源也會(huì)關(guān)閉掉
二、上下文管理器
一個(gè)類(lèi)只要實(shí)現(xiàn)了 __enter__()
和 __exit__()
這個(gè)兩個(gè)方法,通過(guò)該類(lèi)創(chuàng)建的對(duì)象我們就稱(chēng)之為上下文管理器對(duì)象。上下文管理器可以使用 with 語(yǔ)句,with 語(yǔ)句之所以這么強(qiáng)大,背后是由上下文管理器做支撐的,也就是說(shuō)剛才使用 open 函數(shù)創(chuàng)建的文件對(duì)象就是就是一個(gè)上下文管理器對(duì)象。自定義上下文管理器類(lèi),模擬文件操作。定義一個(gè) File 類(lèi),實(shí)現(xiàn) __enter__()
和 __exit__()
方法,然后使用 with 語(yǔ)句來(lái)完成操作文件, 示例代碼:
# -*- coding: utf-8 -*- # @Time : 2022-10-18 10:38 # @Author : AmoXiang # @File : demo4.py # @Software: PyCharm # @Blog : https://blog.csdn.net/xw1680 class File(object): # 初始化方法 def __init__(self, file_name, mode): # 定義變量保存文件名和打開(kāi)模式 self.file_name = file_name self.mode = mode # 上文方法 def __enter__(self): print("進(jìn)入上文方法") # 返回文件資源 self.f = open(self.file_name, self.mode) return self.f # 下文方法 def __exit__(self, exc_type, exc_val, exc_tb): """ with 語(yǔ)句中,即使發(fā)生異常信息,也會(huì)進(jìn)入 __exit__ 中 :param exc_type: 發(fā)生異常時(shí),異常的類(lèi)型 :param exc_val: 發(fā)生異常時(shí),異常的信息 :param exc_tb: 異常對(duì)象,堆棧信息 :return:如果返回False(代碼沒(méi)有書(shū)寫(xiě)返回值默認(rèn)None,表示為False) 代表 異常發(fā)生以后,異常會(huì)繼續(xù)向外傳遞。如果返回True,代表異常不再向外傳遞 """ if exc_type: print("發(fā)生了異常......") return True print("進(jìn)入下文方法") self.f.close() if __name__ == '__main__': with File("1.txt", "r") as file: content = file.read() print(content)
運(yùn)行結(jié)果:
代碼說(shuō)明:
-
__enter__
表示上文方法,需要返回一個(gè)操作文件對(duì)象 -
__exit__
表示下文方法,with 語(yǔ)句執(zhí)行完成會(huì)自動(dòng)執(zhí)行,即使出現(xiàn)異常也會(huì)執(zhí)行該方法。
上下文管理器的另外一種實(shí)現(xiàn)方式: 假如想要讓一個(gè)函數(shù)成為上下文管理器,Python 還提供了一個(gè) @contextmanager
的裝飾器,更進(jìn)一步簡(jiǎn)化了上下文管理器的實(shí)現(xiàn)方式。通過(guò) yield 將函數(shù)分割成兩部分,yield 上面的語(yǔ)句在 __enter__
方法中執(zhí)行,yield 下面的語(yǔ)句在 __exit__
方法中執(zhí)行,緊跟在 yield 后面的參數(shù)是函數(shù)的返回值。示例代碼:
# -*- coding: utf-8 -*- # @Time : 2022-10-18 10:54 # @Author : AmoXiang # @File : demo5.py # @Software: PyCharm # @Blog : https://blog.csdn.net/xw1680 # 導(dǎo)入裝飾器 from contextlib import contextmanager # 裝飾器裝飾函數(shù),讓其稱(chēng)為一個(gè)上下文管理器對(duì)象 @contextmanager def my_open(path, mode): try: # 打開(kāi)文件 file = open(path, mode) # yield之前的代碼好比是上文方法 yield file except Exception as e: print(e) finally: print("over") # yield下面的代碼好比是下文方法 file.close() # 使用with語(yǔ)句 with my_open('out.txt', 'w') as f: f.write("hello , the simplest context manager")
三、小結(jié)
Python 提供了 with 語(yǔ)句 用于簡(jiǎn)化資源釋放的操作,使用 with 語(yǔ)句 操作建立在上下文管理器(實(shí)現(xiàn) __enter__
和 __exit__
) 的基礎(chǔ)上。Python 還提供了一個(gè) @contextmanager
裝飾器,更進(jìn)一步簡(jiǎn)化上下管理器的實(shí)現(xiàn),讓一個(gè)函數(shù)可以成為上下文管理器,結(jié)合 with 語(yǔ)句 來(lái)使用。
原文鏈接:https://blog.csdn.net/xw1680/article/details/127382934
相關(guān)推薦
- 2022-08-03 Python?解析獲取?URL?參數(shù)及使用步驟_python
- 2022-10-12 python繪制發(fā)散型柱狀圖+誤差陰影時(shí)間序列圖+雙坐標(biāo)系時(shí)間序列圖+繪制金字塔圖_python
- 2022-05-01 C#中的三種定時(shí)計(jì)時(shí)器Timer用法介紹_C#教程
- 2022-11-17 React狀態(tài)管理Redux的使用介紹詳解_React
- 2022-05-13 larvel8 批量刪除
- 2023-01-13 基于C#實(shí)現(xiàn)屏幕取色器_C#教程
- 2022-09-24 pandas刪除某行或某列數(shù)據(jù)的實(shí)現(xiàn)示例_python
- 2022-09-25 CopyOnWriteArrayList的源碼分析
- 最近更新
-
- window11 系統(tǒng)安裝 yarn
- 超詳細(xì)win安裝深度學(xué)習(xí)環(huán)境2025年最新版(
- Linux 中運(yùn)行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲(chǔ)小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎(chǔ)操作-- 運(yùn)算符,流程控制 Flo
- 1. Int 和Integer 的區(qū)別,Jav
- spring @retryable不生效的一種
- Spring Security之認(rèn)證信息的處理
- Spring Security之認(rèn)證過(guò)濾器
- Spring Security概述快速入門(mén)
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權(quán)
- redisson分布式鎖中waittime的設(shè)
- maven:解決release錯(cuò)誤:Artif
- restTemplate使用總結(jié)
- Spring Security之安全異常處理
- MybatisPlus優(yōu)雅實(shí)現(xiàn)加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務(wù)發(fā)現(xiàn)-Nac
- Spring Security之基于HttpR
- Redis 底層數(shù)據(jù)結(jié)構(gòu)-簡(jiǎn)單動(dòng)態(tài)字符串(SD
- arthas操作spring被代理目標(biāo)對(duì)象命令
- Spring中的單例模式應(yīng)用詳解
- 聊聊消息隊(duì)列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠(yuǎn)程分支