Python上下文管理—with语句的用法

转载请注明出处: http://blog.csdn.net/jinixin/article/details/72590815

在我阅读Python核心编程有关with语句的部分时,我没有弄懂到底讲了什么?with语句能带来什么好处?后来对它的理解逐渐清晰了起来,所以本文便想谈一谈我对with语句现在的理解,本篇文章之后还会再次更新。
我先介绍with的概念,然后谈一下与其相关的两个方法,最后抛出一个例子。可以结合例子回过头来看这些概念,希望对大家有所帮助。


with的用处


我把with语句理解为对try,except和finally的一种封装。使用with语句可以让程序结构看似更简单,避免代码重复,更加pythonic。 with语句仅能工作于支持上下文管理协议的对象,即该对象必须实现__enter__与__exit__方法。


with的样子

with 表达式[ as 变量]:
    with子语句块

具体例子,如打开文件并打印:

with open('/path/to/file','r') as file:
    for line in file:
        print line,

上述代码在执行完毕时能自动关闭文件,无论是否有异常;甚至通过修改,我们可以让with自动处理异常。总之,with可以让我们把注意力从惦记着释放资源,处理异常等琐事上更多地转移到如何更好的写代码,使程序更高效。



with语句执行流程


这部分可以结合上面with语句结构来看。

首先,with对其后的表达式进行求值,该表达式会返回一个对象,该对象一定包含__enter__与__exit__两个特殊方法。该对象一旦被返回,会立即自动调用__enter__方法,该方法返回的结果会被赋值给as关键字后的变量。此处注意,with后表达式的结果并没有赋值给变量,是__enter__方法的返回值被赋给了该变量。

with语句表达式的作用是返回一个遵循上下文管理协议的对象,即该对象必须实现__enter__与__exit__方法。


实现上下文管理协议的两个必要方法


__enter__:

1)形式:__enter__(self)
2)该方法主要负责在with子语句块执行前进行一些配置。
3) 表达式返回结果对象时,立即调用返回对象的该方法。如果表达式后有as关键字,该方法的返回值被赋值给as后的变量;如果没有as关键字,则该方法的返回值被抛弃。

__exit__:

1)形式:__exit__(self, exc_type, exc_instance, traceback),3个参数分别表示异常类型,异常实例,回溯函数。如果with子句没有发生异常,3个参数全部为None;但一旦发生异常,3个参数便会被填充。
2) 该方法在整个with语句块运行完毕后执行,用于释放资源或处理异常等。即使with子语句块内发生了异常,该方法也一定会执行。
3)当with子语句块发生异常时,会立即执行__exit__方法,__exit__方法可以选择是否处理并“包庇”该异常。当__exit__方法返回为True时,Python解释器会继续执行with语句后面的代码(注意,with子语句块内的后面代码不会被执行),返回False时,则抛出该异常。


例子


最后举一个用到的例子,有关于数据库的(MySQLdb是第三方模块,可通过“pip install mysql-python”安装):
#!/usr/bin/env python
# coding=utf-8

import MySQLdb


class SqlTool(object):

    def __init__(self, db, user='数据库用户', pwd='数据库密码', host='localhost', port=3306):
        self.connect = MySQLdb.connect(user=user, passwd=pwd, host=host, port=port, db=db)  # 创建数据库连接
        self.cursor = self.connect.cursor()  # 创建游标

    def __enter__(self):
        return self.cursor                   # 返回游标给with语句的cursor变量

    def __exit__(self, exc_type, exc_instance, traceback):
        if exc_instance:
            print exc_instance
        self.cursor.close()                  # 关闭游标
        self.connect.commit()                # 确认提交
        self.connect.close()                 # 关闭连接
        return True                          # with语句发生的所有异常都不抛出

with SqlTool(db='test') as cursor:
    cursor.execute('insert into people(name, age) values (%s, %s)', ('jinixin', 20))


参考自Python核心编程第二版10.4节,Python高级编程第2章

文中如有不恰当的地方,还望包容和指出,感谢

猜你喜欢

转载自blog.csdn.net/jinixin/article/details/72590815