目录
原文:https://www.cnblogs.com/nnnkkk/p/4309275.html
with语句
- with语句时在Python2.6中出现的新语句,此前需要使用try/finally代码结构,
-
f = open("test.txt") try: for line in f.readlines(): print(line) finally: f.close()
- with语句的基本语法结构如下 :
-
with expression [as variable]: with-block """ 应用如: with open("text.txt") as f: for line in f.readlines() print(line) """
-
1.首先生成一个上下文管理器expression,在上面例子中with语句首先以“test.txt”作为参数生成一个上下文管理器open("test.txt")。
2.然后执行expression.__enter__()。如果指定了[as variable]说明符,将__enter__()的返回值赋给variable。上例中open("test.txt").__enter__()返回的是一个文件对象给f。
3.执行with-block语句块。上例中执行读取文件。
4.执行expression.__exit__(),在__exit__()函数中可以进行资源清理工作。上面例子中就是执行文件的关闭操作
-
上下文管理器
- 上下文管理器就是实现了上下文协议的类,而上下文协议就是一个类要实现__enter__()和__exit__()两个方法
- __enter__():主要执行一些环境准备工作,同时返回一资源对象。
- 如上下文管理器open("test.txt")的__enter__()函数返回一个文件对象。
- __exit__():资源清理工作。
- 完整形式为__exit__(type, value, traceback),这三个参数分别为异常类型、异常信息和堆栈。如果执行体语句没有引发异常,则这三个参数均被设为None。否则,它们将包含上下文的异常信息
- __exit__()方法返回值为True或False,分别指示被引发的异常有没有被处理。如果返回False,引发的异常将会被传递出上下文
- 如果__exit__()函数内部引发了异常,则会覆盖掉执行体的中引发的异常
- 处理异常时,不需要重新抛出异常,只需要返回False,with语句会检测__exit__()返回False来处理异常。
- __enter__():主要执行一些环境准备工作,同时返回一资源对象。
- 如果我们要自定义一个上下文管理器,只需要定义一个类并且是实现__enter__()和__exit__()即可,以数据库的连接为例。
-
""" 通常的方法 """ def test_write(): con = MySQLdb.connection() cursor = con.cursor() sql = """ #具体的sql语句 """ try: cursor.execute(sql) cursor.execute(sql) cursor.execute(sql) con.commit() #提交事务 except Exception as ex: con.rollback() #事务执行失败,回滚数据库 """ with 方法 """ def test_write(): sql = """ #具体的sql语句 """ con = DBConnection() with con as cursor: cursor.execute(sql) cursor.execute(sql) cursor.execute(sql) def DBConnection(object): def __init__(self): pass def cursor(self): #返回一个游标并且启动一个事务 pass def commit(self): #提交当前事务 pass def rollback(self): #回滚当前事务 pass def __enter__(self): #返回一个cursor cursor = self.cursor() return cursor def __exit__(self, type, value, tb): if tb is None: #没有异常则提交事务 self.commit() else: #有异常则回滚数据库 self.rollback()
-
contextlib模块
-
需要实现一个上下文管理器,需要定义一个实现了__enter__和__exit__两个方法的类, 这显然不是很方便
-
contextlib模块包含一个装饰器contextmanager和一些辅助函数,装饰器contextmanager只需要写一个生成器函数就可以代替自定义的上下文管理器
-
""" 先使用yield先定义一个生成器函数 """ @contextmanager def some_generator(<arguments>): <setup> try: yield <value> finally: <cleanup> """ 然后便可以用with语句调用contextmanage生成的上下文管理器了,with语句用法如下 """ with some_generator(<arguments>) as <variable>: <body> """ 生成器函数some_generator就和我们普通的函数一样,它的原理如下: 1、some_generator函数在在yield之前的代码等同于上下文管理器中的__enter__函数。 2、yield的返回值等同于__enter__函数的返回值,即如果with语句声明了as <variable>,则yield的值会赋给variable 3、然后执行<cleanup>代码块,等同于上下文管理器的__exit__函数。此时发生的任何异常都会再次通过yield函数返回。 """
-