最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

python 上下文管理器及自定義原理解析

 更新時(shí)間:2019年11月19日 14:57:13   作者:-零  
這篇文章主要介紹了python 上下文管理器原理解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下

這篇文章主要介紹了python 上下文管理器原理解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下

Python 提供了 with 語(yǔ)法用于簡(jiǎn)化資源操作的后續(xù)清除操作,是 try/finally 的替代方法,實(shí)現(xiàn)原理建立在上下文管理器之上。

Python 提供了一個(gè) contextmanager 裝飾器,更進(jìn)一步簡(jiǎn)化上下管理器的實(shí)現(xiàn)方式。

上下文管理器是Python2.5之后才出現(xiàn)的概念。上下文管理器規(guī)定了某個(gè)對(duì)象的使用范圍,當(dāng)進(jìn)入或者離開了使用范圍,都會(huì)有相應(yīng)的一些調(diào)用,比如代碼塊開始時(shí)執(zhí)行一些準(zhǔn)備,代碼塊結(jié)束時(shí)結(jié)束一些操作。它更多的是用于資源的分配和釋放上,即在開始時(shí)分配資源,結(jié)束時(shí)釋放一些資源。比如在執(zhí)行數(shù)據(jù)庫(kù)查詢時(shí)要建立連接,查詢結(jié)束后要釋放連接;寫文件時(shí)要先打開文件,寫結(jié)束后,要關(guān)閉文件等等。還有,就是資源的加鎖和解鎖,比如在使用多線程時(shí),可能會(huì)用到加鎖和解鎖。

上下文管理器可以通過使用更可讀、更精簡(jiǎn)的代碼實(shí)現(xiàn)資源的分配與釋放。
復(fù)制代碼

with的使用

對(duì)于上下文管理器的使用,最常見的是使用with語(yǔ)句,with語(yǔ)句可構(gòu)建資源的分配與釋放的語(yǔ)法糖。

因?yàn)閣ith語(yǔ)句就是為支持上下文管理器而存在的,使用上下文管理協(xié)議的方法包裹一個(gè)代碼塊(with語(yǔ)句體)的執(zhí)行,并為try...except...finally提供了一個(gè)方便使用的封裝。

一般語(yǔ)法:

def load_data(filename):
  f = file(filename,'w')
  try:
   f.write('test file')
  finally:
   f.close()

使用with:

# 使用with
with open('test.txt', 'w') as f:
  f.write('Python')

通過 with 語(yǔ)句在編寫代碼時(shí),會(huì)使代碼變得更加簡(jiǎn)潔,不用再去關(guān)閉文件。

我們并不需要寫文件的關(guān)閉操作,文件會(huì)在使用完后自動(dòng)關(guān)閉。

with的執(zhí)行原理

實(shí)際上,在文件操作時(shí),并不是不需要寫文件的關(guān)閉,而是文件的關(guān)閉操作在 with 的上下文管理器中的協(xié)議方法里已經(jīng)寫好了。當(dāng)文件操作執(zhí)行完成后, with語(yǔ)句會(huì)自動(dòng)調(diào)用上下文管理器里的關(guān)閉語(yǔ)句來關(guān)閉文件資源。

上下文管理協(xié)議(context management protocol)
ContextManager ,上下文是 context 直譯的叫法,在程序中用來表示代碼執(zhí)行過程中所處的前后環(huán)境。

上下文管理器中有 __enter__ 和 __exit__ 兩個(gè)方法,以with為例子,__enter__ 方法會(huì)在執(zhí)行 with 后面的語(yǔ)句時(shí)執(zhí)行,一般用來處理操作前的內(nèi)容。比如一些創(chuàng)建對(duì)象,初始化等;__exit__ 方法會(huì)在 with 內(nèi)的代碼執(zhí)行完畢后執(zhí)行,一般用來處理一些善后收尾工作,比如文件的關(guān)閉,數(shù)據(jù)庫(kù)的關(guān)閉等。

上下文管理協(xié)議包括兩個(gè)方法:

contextmanager.__enter__() 從該方法進(jìn)入運(yùn)行時(shí)上下文,并返回當(dāng)前對(duì)象或者與運(yùn)行時(shí)上下文相關(guān)的其他對(duì)象。如果with語(yǔ)句有as關(guān)鍵詞存在,返回值會(huì)綁定在as后的變量上。

contextmanager.__exit__(exc_type, exc_val, exc_tb) 退出運(yùn)行時(shí)上下文,并返回一個(gè)布爾值標(biāo)示是否有需要處理的異常。如果在執(zhí)行with語(yǔ)句體時(shí)發(fā)生異常,那退出時(shí)參數(shù)會(huì)包括異常類型、異常值、異常追蹤信息,否則,3個(gè)參數(shù)都是None。

with語(yǔ)句的語(yǔ)法如下:

with EXPR as VAR:
  BLOCK

with和as是關(guān)鍵詞,EXPR就是上下文表達(dá)式,是任意表達(dá)式(一個(gè)表達(dá)式,不是表達(dá)式列表),VAR是賦值的目標(biāo)變量。"as VAR"是可選的。

上述語(yǔ)句的底層實(shí)現(xiàn)可以這樣描述:

mgr = (EXPR)
exit = type(mgr).__exit__ # 并沒有調(diào)用
value = type(mgr).__enter__(mgr)
exc = True
try:
  try:
    VAR = value # 如果有"as VAR"
    BLOCK
  except:
    # 這里會(huì)處理異常
    exc = False
    if not exit(mgr, *sys.exc_info()):
      raise
    # 如果__exit__返回值是false,異常將被傳播;如果返回值是真,異常將被終止
finally:
  if exc:
    exit(mgr, None, None, None)

這樣with語(yǔ)句的執(zhí)行過程就很清楚了。

  • 執(zhí)行上下文表達(dá)式,獲取上下文管理器
  • 加載上下文管理器的__exit__()方法以備后期調(diào)用
  • 調(diào)用上下文管理器的__enter__()方法
  • 如果with語(yǔ)句有指定目標(biāo)變量,將從__enter__()方法獲取的相關(guān)對(duì)象賦值給目標(biāo)變量
  • 執(zhí)行with語(yǔ)句體
  • 調(diào)用上下文管理器的__exit__()方法,如果是with語(yǔ)句體造成的異常退出,那異常類型、異常值、異常追蹤信息將被傳給__exit__(),否則,3個(gè)參數(shù)都是None。

也可以將多個(gè)表達(dá)式組織在一起。

with A() as a, B() as b:
BLOCK

它等價(jià)于

with A() as a: with B() as b: BLOCK

注:多上下文表達(dá)式是從python 2.7開始支持的

自定義上下文管理器(模擬with打開文件)

要實(shí)現(xiàn)一個(gè)自定義的上下文管理器,肯定要實(shí)現(xiàn)兩個(gè)方法,一是進(jìn)入對(duì)象范圍時(shí)的準(zhǔn)備工作,二是離開對(duì)象范圍時(shí)的結(jié)束工作。

Python提供了兩個(gè)類的方法分別實(shí)現(xiàn)上述功能:

  • __enter__ 進(jìn)入對(duì)象范圍時(shí)(一般代碼塊開始)被調(diào)用;
  • __exit__ 離開對(duì)象范圍時(shí)(代碼塊結(jié)束)唄調(diào)用;

因此,一個(gè)Python類,只要實(shí)現(xiàn)了上述兩種方法,就可以說是一個(gè)上下文管理器。

class MyOpen(object):
  def __init__(self,path,mode):
    # 記錄要操作的文件路徑和模式
    self.__path = path
    self.__mode = mode
 
  def __enter__(self):
    print('代碼執(zhí)行到了__enter__......')
    # 打開文件
    self.__handle = open(self.__path,self.__mode)
    # 返回打開的文件對(duì)象引用, 用來給 as 后的變量f賦值
    return self.__handle
 
  # 退出方法中,用來實(shí)現(xiàn)善后處理工作
  def __exit__(self, exc_type, exc_val, exc_tb):
    print('代碼執(zhí)行到了__exit__......')   
    self.__handle.close()
 
# a+ 打開一個(gè)文件用于讀寫。如果該文件已存在,文件指針將會(huì)放在文件的結(jié)尾。文件打開時(shí)會(huì)是追加模式。如果該文件不存在,創(chuàng)建新文件用于讀寫。
with MyOpen('test.txt','a+') as f:
  # 創(chuàng)建寫入文件
  f.write("Hello Python!!!")
  print("文件寫入成功")

通過執(zhí)行順序,可以看到文件寫入操作執(zhí)行完之后,自動(dòng)調(diào)用了__exit__方法,做了善后處理工作。

代碼執(zhí)行到了__enter__......
文件寫入成功
代碼執(zhí)行到了__exit__...... 
 

__exit__方法的參數(shù)

__exit__ 方法中有三個(gè)參數(shù),用來接收處理異常,如果代碼在運(yùn)行時(shí)發(fā)生異常,異常會(huì)被保存到這里。

exc_type : 異常類型

exc_val : 異常值

exc_tb : 異?;厮葑粉?/p>

# 編寫兩個(gè)數(shù)做除法的程序,然后給除數(shù)穿入0
class MyCount(object):
  # 接收兩個(gè)參數(shù)
  def __init__(self,x, y):
    self.__x = x
    self.__y = y
  # 返回一個(gè)地址(實(shí)質(zhì)是被as后的變量接收),實(shí)例對(duì)象就會(huì)執(zhí)行MyCount中的方法:div()
  def __enter__(self):
    print('代碼執(zhí)行到了__enter__......')
    return self
  def __exit__(self, exc_type, exc_val, exc_tb):
    print("代碼執(zhí)行到了__exit__......")
    if exc_type == None:
      print('程序沒問題')
    else:
      print('程序有問題,如果你能你看懂,問題如下:')
      print('Type: ', exc_type)
      print('Value:', exc_val)
      print('TreacBack:', exc_tb)
 
    # 返回值決定了捕獲的異常是否繼續(xù)向外拋出
    # 如果是 False 那么就會(huì)繼續(xù)向外拋出,程序會(huì)看到系統(tǒng)提示的異常信息
    # 如果是 True 不會(huì)向外拋出,程序看不到系統(tǒng)提示信息,只能看到else中的輸出
    return True
 
  def div(self):
    print("代碼執(zhí)行到了除法div")
    return self.__x / self.__y
with MyCount(1, 0) as mc:
  mc.div()

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • python 函數(shù)的詳解與應(yīng)用范例

    python 函數(shù)的詳解與應(yīng)用范例

    函數(shù)是組織好的,可重復(fù)使用的,用來實(shí)現(xiàn)單一,或相關(guān)聯(lián)功能的代碼段。函數(shù)能提高應(yīng)用的模塊性,和代碼的重復(fù)利用率。你已經(jīng)知道Python提供了許多內(nèi)建函數(shù),比如print()。但你也可以自己創(chuàng)建函數(shù),這被叫做用戶自定義函數(shù)
    2021-11-11
  • python PyQt5中QRadioButton的詳細(xì)使用教程與應(yīng)用實(shí)戰(zhàn)

    python PyQt5中QRadioButton的詳細(xì)使用教程與應(yīng)用實(shí)戰(zhàn)

    PyQt5是一個(gè)跨平臺(tái)的GUI工具包,用于創(chuàng)建具有Python綁定的Qt應(yīng)用程序,在PyQt5中,QRadioButton是一個(gè)非常有用的控件,用于在用戶界面上提供單選選項(xiàng),本文將詳細(xì)介紹QRadioButton的基本用法、常用屬性和方法,需要的朋友可以參考下
    2024-08-08
  • Python實(shí)現(xiàn)從腳本里運(yùn)行scrapy的方法

    Python實(shí)現(xiàn)從腳本里運(yùn)行scrapy的方法

    這篇文章主要介紹了Python實(shí)現(xiàn)從腳本里運(yùn)行scrapy的方法,實(shí)例分析了Python腳本運(yùn)行的使用技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2015-04-04
  • Python多進(jìn)程加鎖的實(shí)現(xiàn)

    Python多進(jìn)程加鎖的實(shí)現(xiàn)

    很多時(shí)候,我們需要在多個(gè)進(jìn)程中同時(shí)寫一個(gè)文件,如果不加鎖機(jī)制,就會(huì)導(dǎo)致寫文件錯(cuò)亂,本文主要介紹了Python多進(jìn)程加鎖的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),感興趣的可以了解一下
    2023-07-07
  • tkinter如何實(shí)現(xiàn)打開文件對(duì)話框并獲取文件絕對(duì)路徑

    tkinter如何實(shí)現(xiàn)打開文件對(duì)話框并獲取文件絕對(duì)路徑

    這篇文章主要介紹了tkinter實(shí)現(xiàn)打開文件對(duì)話框并獲取文件絕對(duì)路徑問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-01-01
  • python批量生成本地ip地址的方法

    python批量生成本地ip地址的方法

    這篇文章主要介紹了python批量生成本地ip地址的方法,實(shí)例分析了Python實(shí)現(xiàn)生成本地IP地址并綁定到網(wǎng)卡上的技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2015-03-03
  • 通過pycharm的database設(shè)置進(jìn)行數(shù)據(jù)庫(kù)的可視化方式

    通過pycharm的database設(shè)置進(jìn)行數(shù)據(jù)庫(kù)的可視化方式

    這篇文章主要介紹了通過pycharm的database設(shè)置進(jìn)行數(shù)據(jù)庫(kù)的可視化方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-09-09
  • pycharm+django創(chuàng)建一個(gè)搜索網(wǎng)頁(yè)實(shí)例代碼

    pycharm+django創(chuàng)建一個(gè)搜索網(wǎng)頁(yè)實(shí)例代碼

    這篇文章主要介紹了pycharm+django創(chuàng)建一個(gè)搜索網(wǎng)頁(yè)實(shí)例代碼,分享了相關(guān)代碼示例,小編覺得還是挺不錯(cuò)的,具有一定借鑒價(jià)值,需要的朋友可以參考下
    2018-01-01
  • Python調(diào)用PC攝像頭實(shí)現(xiàn)掃描二維碼

    Python調(diào)用PC攝像頭實(shí)現(xiàn)掃描二維碼

    PC攝像機(jī)掃描二維碼的應(yīng)用場(chǎng)景很廣泛,可以應(yīng)用于各種需要快速掃描、識(shí)別和管理的場(chǎng)景,本文就來具體講講如何用Python實(shí)現(xiàn)這一功能吧
    2023-05-05
  • 詳解Python 函數(shù)如何重載?

    詳解Python 函數(shù)如何重載?

    這篇文章主要介紹了Python函數(shù)重載,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-04-04

最新評(píng)論

景洪市| 舞阳县| 平和县| 黄浦区| 弋阳县| 乌什县| 福清市| 岳普湖县| 广州市| 林西县| 玉环县| 邵阳市| 巴塘县| 呼伦贝尔市| 前郭尔| 建水县| 青阳县| 亳州市| 陇川县| 泸州市| 巴林右旗| 密云县| 台北市| 绥德县| 梁山县| 榆林市| 嵩明县| 城固县| 海盐县| 辽宁省| 镇安县| 土默特左旗| 兴义市| 九江县| 山西省| 合作市| 锡林浩特市| 全椒县| 紫云| 上虞市| 都江堰市|