python的with語句和上下文管理器初窺

在編程中,遇到with語句有好幾次了,一直對with是一知半解,前兩天在看書的時候,突然看到了這個問題,茅塞頓開啊,爲了防止以後又塞了,寫個博客備忘。
程序的上下文我一直不太理解,在看了書之後,得出如此的結論:上下文就是某段代碼的運行環境。上下文管理器的作用就是在某段代碼需要運行的時候,給代碼創造環境,在運行完之後,給收拾了,不要讓那段代碼老佔着板凳不吃涼粉。上下文管理器和with語句的關係就是with語句可以進入上下文管理器。
python中的有些內置函數帶了上下文管理器,比如open方法,用來打開文件,不用with的情況下,在打開文件使用後並關閉文件,正確的方法應該是如下的操作:

try:
    f = open('/path/to/filename', 'r')
    # do something
finally:
    f.close()

不論執行了什麼操作,最後都應該把文件關掉,這就是finally語句的作用,那麼使用with語句是什麼樣的呢?

with open('path/to/filename', 'r') as f:
    # do something

是不是簡潔了很多,在代碼執行完之後,文件就關閉了,當然使用的還是close方法,但是open中的上下文管理器替我們做了。
with語句對它後面的代碼進行求值,就是問後面的語句要一個返回值,比如這個open,會讓open返回一個對象,這個對象就包含兩個方法,當然是比較特殊的方法,enter方法和exit方法,enter()方法返回的值會賦給as關鍵字之後的變量。
with語句的作用就是返回一個遵循特定協議的對象,這個對象必須定義一個enter和一個exit方法,而且exit必須接受特定的參數,而enter方法除了self之外,不接受任何參數,enter負責進行一些配置。exit帶有三個位置參數,加上self有四個,如果沒有異常,全部設爲None。有一段連接數據庫的代碼如下,其中寫了上下文管理器。

import psycopg2

class DBConnect(object):
    def __init__(self, dbname=None, user=None, password=None, host='localhost', port='5432'):
        self.hsot = host
        self.port = port
        self.dbname = dbname
        self.user = user
        self.password = password
    # __enter__函數,連接數據庫,並且返回遊標
    def __enter__(self):
        self.connection = psycopg2.connect(
            dbname = self.dbname,
            host = self.host,
            user = self.user,
            password = self.password,
            port = self.port,
        )
        return self.connection.cursor()    #返回一個遊標
    # __exit__ 函數,最後斷開連接
    def __exit__(self, exc_type, exc_instance, trackeback):
        self.connection.close()

上面的一段代碼就是一個上下文管理器,用來連接postgresql數據庫的上下文管理器,使用的時候如下:

with DBConnect(user='username', dbname='database_name') as db:
    db.execute('select * from a_sheet')
    db.fetchall()

以上的代碼中,with語句後面的部分,在運行後由上面定義的 enter 方法返回的遊標對象,然後as又將這個遊標對象賦值給變量db,然後對數據庫進行一個操作,當操作完成後,或者操作出現錯誤,總之,無論發生什麼情況,在最後,上下文管理器都會關閉這個連接。
簡言之,上下文管理器就是在使用某些資源的時候打開,不使用的時候正確並且及時的關閉。
而with語句和上下文管理器的關係就是:with能使用上下文管理器,可以進入上下文管理器。

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