python 上下文管理器

python的上下文管理器看了很多解釋

vamei的python教程

上下文管理器(context manager)是Python2.5開始支持的一種語法,用於規定某個對象的使用範圍。一旦進入或者離開該使用範圍,會有特殊操作被調用 (比如爲對象分配或者釋放內存)。它的語法形式是with...as...

 

python編程時光

1. 上下文表達式:with open('test.txt') as f:

2. 上下文管理器:open('test.txt')

3. f 不是上下文管理器,應該是資源對象。

 

個人理解是對資源的一些操作!

上下文管理器的實現有兩種方式,我用1/0這個例子來展示一下


第一種方式:

"""
一個類實現了 __enter__和__exit__的方法,這個類的實例就是一個上下文管理器
"""

import traceback

class Resource():
    def __enter__(self):
        """
        我們可以將一些資源初始化動作放在 __enter__ 
        比如:數據庫連接,打開文件
        一般返回資源對象
        """
        print('=== __enter__ ===')
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        """
         __exit__ 包含三個參數:
        exc_type 異常類型
        exc_val 異常值
        exc_tb 異常的錯誤棧信息
        當沒有異常時三個都是None
        __exit__ 包含了異常捕捉和結束動作
        """
        print(exc_type, exc_val, traceback.print_tb(exc_tb))
        print('==== __exit__ ====')
        return True

    def zero_func(self, x):
        print(1/x)

with Resource() as res:
    """
    as 會把 __enter__ 返回值賦給 目標 res
    如果我們讓 __enter__ return 1,在這裏我們print(res),會發現res的值是1,
    如果我們在這裏print(res),會發現先執行 __enter__ 再 執行__exit__
    """
    res.zero_func(0)
    """
    1/0 原本是會報錯的,
    但是這裏如果沒有在 __exit__ 打印錯誤信息的話,這裏是不會有異常信息的
    """

 

第二種方式:

"""
通過contextlib 創建上下文管理器
"""

import traceback
import contextlib

# 使用修飾器 @contextlib.contextmanager
@contextlib.contextmanager
def zero_func(x):
    # yield 之前的 都相當於 __enter__ 的內容
    print('====== __enter__ =========')

    try:
        """
        yield 後面可以返回一個對象,相當於 __enter__ 的return
        """
        yield
        """
        yield 後面的內容相當於__exit__
        """
        zero_parameter = 1/x
    except Exception as exc:
        # 處理異常
        """
        如果使用traceback.print_exc()會返回一個空對象
        錯誤信息的打印有可能出現在__exit__之後
        """
        print(traceback.format_exc())
    else:
        # 沒異常執行部分
        print(zero_parameter) 
    finally:
        # 結束
        print('===== 結束 ====')

with zero_func(0) as x:
    """
    這裏print(x)會發現打印出一個None,這個其實是yield返回的空對象
    這裏還能看出來,print(x) 雖然在後面但是執行的時候是先執行
    """
    print(x)

 

實戰用兩種上下文管理器實現打開文件:

第一種:

import traceback

class OpenFiles():
    def __init__(self, filename, openway):
        print('==== __init__ ====')
        self.filename = filename
        self.openway = openway
        self.file_obj = None

    def __enter__(self):
        print('==== __enter__ ====')
        self.file_obj = open(self.filename, self.openway)
        return self.file_obj

    def __exit__(self, exc_type, exc_val, exc_tb):
        print(exc_type, exc_val, traceback.print_tb(exc_tb))
        if self.file_obj:
            self.file_obj.close()
        print('==== __exit__ ====')
        return True

with OpenFiles('text.txt', 'r') as res:
    """
    如果test.txt不存在會報錯,你可以用w創建一個,然後打開往裏面寫點東西,在改爲r
    python 中如果文件不存在,r r+會報錯,w w+ a a+ 會創建
    """
    print(res.readlines())

 

第二種:

import traceback
import contextlib

@contextlib.contextmanager
def open_file(filename, openway):
    print('====== __enter__ =========')
    try:
        file_obj = open(filename, openway)
        yield file_obj
        print('====== __exit__ =========')
    except Exception as exc:
        print(traceback.format_exc())
    else:
        pass
    finally:
        file_obj.close()

with open_file('text.txt', 'r') as res:
    print(res.readlines())

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章