博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
上下文管理器
阅读量:5890 次
发布时间:2019-06-19

本文共 3236 字,大约阅读时间需要 10 分钟。

hot3.png

1.什么是上下文管理器

  • 先来说一下什么是上下文管理器吧,其实上下文管理器就是一个包装任意代码块的对象,上下文管理器保证进入上下文管理器时,每次代码执行的一致性,当退出上下文管理器时,相关的资源会被正确的回收。使用上下文管理器的好处是,一定能够保证退出步骤的执行,通过 with 语句在编写代码时,会使代码变得更加简洁,不用再去关闭文件

2.如何实现上下文管理器

我们通过实例来看一下如何实现上下文管理器:

class Student:    def __init__(self):   # 第一步:首先进入上下文之前会调用初始化方法        print('init')        self.name = '张三'        self.age = 27    def __enter__(self):   # 第二步:然后进入上下文会调用__enter__方法,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模块装饰器和生成器实现上下文管理;

with 语句实现的上下文管理

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('自定义抛出一个异常')
# 数据库连接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子句,它们两者可以相互转换;

contextlib模块实现上下文管理器

# 让普通函数也可以使用上下文管理, 前提条件是add函数必须是生成器函数,且只有yield语句from contextlib import contextmanager@contextmanagerdef 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( )方法!);

3.functools.total_ordering装饰器

使用functools.total_ordering装饰器可以很方便让实例比较大小:

from functools import total_ordering@total_orderingclass Student:    def __init__(self, price):        self.__price = price    @property    def price(self):        return self.__price    # 如果需要比较大小,必须实现'< > <= >='一个其中的一个    def __lt__(self, other):        return self.__price < other.__pricestu1 = Student(10)stu2 = Student(19)print(stu1 < stu2)print(stu1 > stu2)# 输出:TrueFalse
  • functools.total_ordering装饰器是在python2.7的时候加上的,它是针对某个类如果定义了__lt____le____gt____ge__这些方法中的至少一个,使用该装饰器,则会自动的把其他几个比较函数也实现在该类中 例如上面的实例,我们只定义了__lt__()方法,本来如果我们使用,但是却能使用__gt__()方法是会报错的,但是用了functools.total_ordering装饰器之后却能使用__gt__()方法了,是不是很方便;

参考:

转载于:https://my.oschina.net/u/4072026/blog/3035994

你可能感兴趣的文章
iOS8中定位服务的变化(CLLocationManager协议方法不响应,无法回掉GPS方法,不出现获取权限提示)...
查看>>
BeanUtils\DBUtils
查看>>
VC 创建托盘,托盘tooltip。右键托盘菜单,点击别的地方会隐藏掉的问题。
查看>>
第一天,新的定义
查看>>
WPF EventSetter Handler Command
查看>>
polya定理,环形涂色
查看>>
day4-装饰器前奏
查看>>
forward和redirect的区别
查看>>
使用JavaMail完成邮件的编写
查看>>
洛谷P1576 最小花费
查看>>
封装了一个类,可生成验证码,缩略图,及水印图
查看>>
文件服务器 之 Debian下pureftpd的安装心得
查看>>
第一阶段项目总结
查看>>
Java集合详解
查看>>
myeclilpse打开文件所在位置的图标消失后的找回方法
查看>>
Android利用文本分割拼接开发一个花藤文字生成
查看>>
哈夫曼树的实现
查看>>
12-18Windows窗体应用小程序之记事本(1)
查看>>
毕业论文一次性修改所有字母和数字的字体
查看>>
结构体:HASH表模板
查看>>