iT邦幫忙

0

[Python] 關於 with 你所不知道的事

相信用 C 語言寫過檔案讀取的人都知道,經常開檔後就忘記關檔,或者程式中間跳出例外,因此沒有關檔。這些問題常常讓人非常頭痛?。

所幸 Python 中有 with 這個語法糖,可以自動幫你開關檔,跳出例外也難不倒他,真的非常好用。

但你真的了解 with 背後的運行原理嗎? ?

不知道沒關係,因為你現在就會知道了!

context manager

在講 with 之前,必須先介紹一下 context manager,中文可以翻成 情境管理器

為什麼叫做 情境管理器 呢? 我們試想一個情境...

當你進入房間時,就要開啟房間的燈:然後當你離開房間時,就要關閉房間的燈。

像這樣理所當然一定要做的事情,我們就稱為一個情境。而 Python 就是透過情境管理器處理這些情境。

要自己實作 context manager 其實很簡單,只要在 Class 中實作 __enter__()__exit__() 即可。

就以進入房間當作例子。

class Room():
    def turn_on_light(self):
        print("開燈")

    def turn_off_light(self):
        print("關燈")

    def __enter__(self):
        print("進入房間")
        self.turn_on_light()
        return "在房間裡"

    def __exit__(self, exc_type, exc_value, traceback):
        self.turn_off_light()
        print("離開房間")

with Room() as room:
    print(room)

執行之後會印出以下結果:

進入房間
開燈
在房間裡
關燈
離開房間

這非常的直覺,當我們宣告 with Room() 時,就會自動去呼叫 Room() 裡面的 __enter__() 這個函數。後面的 room 就是回傳的字串 "在房間裡" 哦!

當程式離開 with 的範圍時,就會自動去呼叫 __exit__() 這個函數。這多了三個參數分別是 exc_type (例外型態), exc_value (例外值), traceback (錯誤追蹤結果),下一個例子示範如何使用這三個參數。

class Room():
    def turn_on_light(self):
        print("開燈")

    def turn_off_light(self):
        print("關燈")

    def __enter__(self):
        print("進入房間")
        self.turn_on_light()
        return "在房間裡"

    def __exit__(self, exc_type, exc_value, traceback):
        if not exc_type:
            self.turn_off_light()
            print("離開房間")
        else:
            print("Exception type:", exc_type)
            print("Exception value:", exc_value)
            print("Traceback:", traceback)

with Room() as room:
    print(i)    # NameError

執行結果:

進入房間
開燈
Exception type: <class 'NameError'>
Exception value: name 'i' is not defined
Traceback: <traceback object at 0x0000023862DD4700>
Traceback (most recent call last):
  File "D:\Andy\Code\test_with\test02.py", line 26, in <module>
    print(i)
NameError: name 'i' is not defined. Did you mean: 'id'?

我故意使用一個沒宣告過的變數,讓程式跳出 NameError,然後就會直接呼叫 __exit__(),並傳入錯誤訊息的參數。如果正常沒出錯的情況,exc_type 會是 None,就會去執行原本的程式 (關燈)。

所以 Python 常用的 open() 實際上就是一個 context manager,__enter__() 就寫開檔相關的程式,__exit__() 則寫關檔相關的程式,就完成啦!

偶爾去研究一下 Python 一些語法的實作也滿有趣的呢?

參考資料


圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言