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能使用上下文管理器,可以进入上下文管理器。

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