1.什么是上下文管理
上下文管理器是一个包装任意代码块的对象,上下文管理器保证进入上下文管理器时,每次代码执行的一致性,当退出上下文管理器时,相关的资源会被正确的回收;上下文管理器一定能够保证退出步骤的执行,不用再调用close()关闭文件;2.如何实现上下文管理器
class Student: def __init__(self): # 之一步:进入上下文之前会调用初始化 print('init') self.name = '张三' self.age = 27 def __enter__(self): # 第二步:进入上下文会调用这个 ,return返回的结果会通过as关键字赋值给后面的变量 print('enter') return self def __exit__(self, exc_type, exc_val, exc_tb): print('exit') # 第四步:执行完毕语句块后,会调用__exit__ 退出上下文 with Student() as stu: print(stu) # 第三步:调用了__enter__后,会执行上下文的语句块 实现上下文管理器有两种方式,一个是通过类实现__enter__和__exit__ ,也就是通过with语句进行上下文管理;第二种是通过contextlib模块装饰器和生成器实现上下文管理;
3.with 语句的上下文管理
# 示例1 class Student: def __init__(self): print('init') self.name = '张三' self.age = 27 def __enter__(self): print('enter') return self def __exit__(self, exc_type, exc_val, exc_tb): print('exit') # 即使在上下文语句中出现异常,那么退出上下文的时候,也会执行__exit__ with Student() as stu: raise Exception('自定义抛出一个异常') # 示例2(数据库连接) class Data: def __init__(self): self.influxdb_client_1 = InfluxDBClient(host='1.1.1.1', port=8086, database='database1', ) self.influxdb_client_2 = InfluxDBClient(host='2.2.2.2', port=8086, database='database1', ) def __enter__(self): return self def __exit__(self, exc_type, exc_val, exc_tb): self.influxdb_client_1.close() self.influxdb_client_2.close() def get_metrics(self, server_name): print('从influxdb中查询到所有的metrics') return '将所有的metrics返回' # 使用上下文管理查询数据的过程, 即使中间抛出异常,也会执行__exit__ ,关闭数据库连接 with Data() as data: data.get_metrics(server1) with语句的语法为:with 表达式 [as 目标]:代码块;当with遇到上下文管理器,就会在执行语句体之前,先执行上下文管理器的__enter__ ,然后再执行语句体,执行完语句体后,最后执行__exit__ ;with语句支持嵌套,支持多个with子句,它们两者可以相互转换;
4.contextlib模块
# 让普通函数也可以使用上下文管理, 前提条件是add函数必须是生成器函数,且只有yield语句 from contextlib import contextmanager @contextmanager def add(x, y): print('__enter__') # 第二部:调用__enter__ yield x + y # 第二部:返回__enter__函数的返回值给obj对象 print('__exit__') # 第四部:调用__exit__ with add(1,2) as obj: print(obj) # 第三部:执行上下文语句块 contextlib模块是Python标准库提供的更加易用的上下文管理器工具模块;它是通过装饰器实现的,不需要再创建类以及使用__enter__和__exit__这两个 ,比with语句更加方便;@contextmanager是一个装饰器decorator,它接收一个生成器generator,把生成器里yield的值赋给with...as后的变量,然后正常执行with语句;closing 也是一个经过 @contextmanager 装饰的装饰器,closing( )可以把对象变为上下文对象,然后使用with语句(前提是这个对象能调用close( ) !);
5.functools.total_ordering装饰器
# 让实例比较大小很方便 from functools import total_ordering @total_ordering class XKD: def __init__(self, price): self.__price = price @property def price(self): return self.__price # 如果需要比较大小,必须实现'< > <= >='一个其中的一个 def __lt__(self, other): return self.__price < other.__price xkd1 = XKD(100) xkd2 = XKD(200) print(xkd1 <= xkd2) 这个装饰器是在python2.7的时候加上的,它是针对某个类如果定义了__lt__、__le__、__gt__、__ge__这些 中的至少一个,使用该装饰器,则会自动的把其他几个比较函数也实现在该类中;
参考:https://www.9xkd.com/user/plan-view.html?id=2808881948