浅淡python中with的用法,上下文管理器
例子一
首先来看一段代码:
class Foo(object):
def __init__(self):
print('实例化一个对象')
def __enter__(self):
print('进入')def __exit__(self, exc_type, exc_val, exc_tb):
print('退出')
obj = Foo()
with obj:
print('正在执行')
上面代码执行结果为:
实例化一个对象
进入
正在执行
退出
结论1
我们知道,实例化Foo,得到obj对象,会执行Foo的__init__方法,也就是打印了第一句;
按照,程序从上至下执行,应该会打印“正在执行”才对,为什么会在它之前先打印了进入,在它之后打印了退出呢?
因为我们在定义Foo时,定义了__enter__和__exit__方法,那么我们实例化的对象obj就是一个上下文管理器,
即含有__enter__和__exit__方法的对象就是上下文管理器。
with 上下文管理器:
语句体
当with遇到上下文管理器,就会在执行语句体之前,先执行上下文管理器的__enter__方法,然后再执行语句体,执行完语句体后,最后执行__exit__方法
这也就是为什么会出现文章开头的情况的原因。
例子二
再看看这段代码:
class Foo(object):
def __init__(self):
print('实例化一个对象')
def __enter__(self):
print('进入')
def __exit__(self, exc_type, exc_val, exc_tb):
print('退出')
# return True
obj = Foo()
with obj:
raise ImportError
print('正在执行')
结果如下:
把上面代码中我们注释掉的那一行代码取消注释,结果如下
我们会发现,虽然我们故意在语句体中抛出一个错误,按照正常情况,执行到报错地方就不会执行了,而__exit__是在语句体执行完之后执行的,但还是执行了__exit__方法;当我们在__exit__中给一个返回值为Ture时,就会忽略错误。
结论2
所有我们可以发现
with语句类似
try :
except:
finally:
的功能:但是with语句更简洁。而且更安全。代码量更少。
出现异常时,如果 __exit__ 返回 False(默认不写返回值时,即为False),则会重新抛出异常,让with 之外的语句逻辑来处理异常,这也是通用做法;如果返回 True,则忽略异常,不再对异常进行处理
例子三
class Foo(object):
def __init__(self):
print('实例化一个对象')
def __enter__(self):
print('进入')
# return self
def __exit__(self, exc_type, exc_val, exc_tb):
print('退出')
with Foo() as obj:
print(obj,type(obj))
print('正在执行')
把上面代码中我们注释掉的那一行代码取消注释,结果如下
结论
调用上下文管理器的 __enter__ 方法时;如果使用了 as 子句,则将 __enter__() 方法的返回值赋值给 as 子句中的目标
with 上下文管理器 as target:
代码语句体
with后面必须跟一个上下文管理器,如果使用了as,则是把上下文管理器的 __enter__() 方法的返回值赋值给 target,target 可以是单个变量,或者由“()”括起来的元组(不能是仅仅由“,”分隔的变量列表,必须加“()”)
例子四
我们经常会看到这样的代码:
with open("/tmp/foo.txt") as file:
data = file.read()
结论
这里使用了 with 语句,不管在处理文件过程中是否发生异常,都能保证 with 语句执行完毕后已经关闭了打开的文件句柄。如果使用传统的 try/finally 范式,则要使用类似如下代码:
somefile = open(r'somefileName')
try:
for line in somefile:
print line
# ...more code
finally:
somefile.close()
比较起来,使用 with 语句可以减少编码量。已经加入对上下文管理协议支持的还有模块 threading、decimal 等。
补充
with只能配合上下文管理器使用,常见的上下文管理器有
file
decimal.Context
thread.LockType
threading.Lock
threading.RLock
threading.Condition
threading.Semaphore
threading.BoundedSemaphore
- 萌新刷题(十三)买卖股票的最佳时机
- 萌新刷题(十一)有效数字
- Hive性能优化统计每日IP CREATE TABLE ip_2014_12_29 AS SELECT COUNT(DISTINCT ip) AS IP FROM logdfs WHERE logda
- 算法中描述复杂度的大O是什么意思?
- 优化Mysql:3个简单的调整
- Redis的5个常见应用场景
- Mysql 索引你了解多少?
- Mysql 8 新特性 window functions 有什么用?
- 用两张图告诉你,为什么你的App会卡顿?
- MapReduce设计模式
- 一个Sqrt函数引发的血案
- 小程序优秀开发资源
- Redis 新数据结构 - Streams
- Kafka 是否可以用做长期数据存储?
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法