with语法
上下文管理协议
要使用 with 语句,首先要明白上下文管理器这一概念。有了上下文管理器,with 语句才能工作。
下面是一组与上下文管理器和with 语句有关的概念。
上下文管理协议(Context Management Protocol):包含方法 __enter__() 和 __exit__(),支持该协议的对象要实现这两个方法。
上下文管理器(Context Manager):支持上下文管理协议的对象,这种对象实现了__enter__() 和 __exit__() 方法。上下文管理器定义执行 with 语句时要建立的运行时上下文,负责执行 with 语句块上下文中的进入与退出操作。通常使用 with 语句调用上下文管理器,也可以通过直接调用其方法来使用。
运行时上下文(runtime context):由上下文管理器创建,通过上下文管理器的 __enter__() 和__exit__() 方法实现,__enter__() 方法在语句体执行之前进入运行时上下文,__exit__() 在语句体执行完后从运行时上下文退出。with 语句支持运行时上下文这一概念。
上下文表达式(Context Expression):with 语句中跟在关键字 with 之后的表达式,该表达式要返回一个上下文管理器对象。
语句体(with-body):with 语句包裹起来的代码块,在执行语句体之前会调用上下文管理器的 __enter__() 方法,执行完语句体之后会执行__exit__() 方法。
with如何工作?
- 紧跟with后面的语句被求值后,返回对象的 __enter__() 方法被调用,这个方法的返回值将被赋值给as后面的变量。
- 当with后面的代码块全部被执行完之后,将调用前面返回对象的 __exit__()方法。
class Sample:
def __enter__(self):
print("In __enter__()")
return "Foo"
def __exit__(self, type, value, trace):
print("In __exit__()")
def get_sample():
return Sample()
with get_sample() as sample:
# 表达式返回的对象要实现__enter__与__exit__方法
print("sample:", sample) # 打印内容
In __enter__()
sample: Foo
In __exit__()
with真正强大之处是它可以处理异常。
可能你已经注意到Sample类的 __exit__ 方法有三个参数 val, type 和 trace。 这些参数在异常处理中相当有用。我们来改一下代码,看看具体如何工作的。
_type = type
class Sample:
def __enter__(self):
return self # 返回了实例自身
def __exit__(self, type, value, trace):
print("type:", type,_type(type)) # 类
print("value:", value,_type(value)) # 实例
print("trace:", trace,_type(trace))
def do_something(self):
bar = 1/0
return bar + 10
with Sample() as sample:
sample.do_something()
执行结果
type: <class 'ZeroDivisionError'> <class 'type'>
Traceback (most recent call last):
value: division by zero <class 'ZeroDivisionError'>
File "D:/python/luffy_2/test.py", line 15, in <module>
trace: <traceback object at 0x000001E8E7BCEB88> <class 'traceback'>
sample.do_something()
File "D:/python/luffy_2/test.py", line 12, in do_something
bar = 1/0
ZeroDivisionError: division by zero
实际上,在with后面的代码块抛出任何异常时,__exit__() 方法被执行。正如例子所示,异常抛出时,与之关联的type,value和stack trace传给 __exit__() 方法,因此抛出的ZeroDivisionError异常被打印出来了。开发库时,清理资源,关闭文件等等操作,都可以放在 __exit__ 方法当中。
另外,__exit__ 除了用于tear things down,还可以进行异常的监控和处理,注意后几个参数。要跳过一个异常,只需要返回该函数True即可。
更改上面代码
_type = type
class Sample:
def __enter__(self):
return self
def __exit__(self, type, value, trace):
print("type:", type,_type(type)) # 类
print("value:", value,_type(value)) # 实例
print("trace:", trace,_type(trace))
return isinstance(value, ZeroDivisionError)
def do_something(self):
bar = 1/0
return bar + 10
with Sample() as sample:
sample.do_something()
执行结果
type: <class 'ZeroDivisionError'> <class 'type'>
value: division by zero <class 'ZeroDivisionError'>
trace: <traceback object at 0x000001195FDDEBC8> <class 'traceback'>
with语法的更多相关文章
- 我的MYSQL学习心得(一) 简单语法
我的MYSQL学习心得(一) 简单语法 我的MYSQL学习心得(二) 数据类型宽度 我的MYSQL学习心得(三) 查看字段长度 我的MYSQL学习心得(四) 数据类型 我的MYSQL学习心得(五) 运 ...
- Swift与C#的基础语法比较
背景: 这两天不小心看了一下Swift的基础语法,感觉既然看了,还是写一下笔记,留个痕迹~ 总体而言,感觉Swift是一种前后端多种语言混合的产物~~~ 做为一名.NET阵营人士,少少多多总喜欢通过对 ...
- 探索C#之6.0语法糖剖析
阅读目录: 自动属性默认初始化 自动只读属性默认初始化 表达式为主体的函数 表达式为主体的属性(赋值) 静态类导入 Null条件运算符 字符串格式化 索引初始化 异常过滤器when catch和fin ...
- [C#] 回眸 C# 的前世今生 - 见证 C# 6.0 的新语法特性
回眸 C# 的前世今生 - 见证 C# 6.0 的新语法特性 序 目前最新的版本是 C# 7.0,VS 的最新版本为 Visual Studio 2017 RC,两者都尚未进入正式阶段.C# 6.0 ...
- Velocity初探小结--velocity使用语法详解
做java开发的朋友一般对JSP是比较熟悉的,大部分人第一次学习开发View层都是使用JSP来进行页面渲染的,我们都知道JSP是可以嵌入java代码的,在远古时代,java程序员甚至在一个jsp页面上 ...
- node.js学习(二)--Node.js控制台(REPL)&&Node.js的基础和语法
1.1.2 Node.js控制台(REPL) Node.js也有自己的虚拟的运行环境:REPL. 我们可以使用它来执行任何的Node.js或者javascript代码.还可以引入模块和使用文件系统. ...
- C#语法糖大汇总
首先需要声明的是"语法糖"这个词绝非贬义词,它可以给我带来方便,是一种便捷的写法,编译器会帮我们做转换:而且可以提高开发编码的效率,在性能上也不会带来损失.这让java开发人员羡慕 ...
- 值得注意的ibatis动态sql语法格式
一.Ibatis常用动态sql语法,简单粗暴用一例子 <select id="iBatisSelectList" parameterClass="java.util ...
- Flex 布局教程:语法篇
作者: 阮一峰 网页布局(layout)是CSS的一个重点应用. 布局的传统解决方案,基于盒状模型,依赖 display属性 + position属性 + float属性.它对于那些特殊布局非常不方便 ...
- postgresql 基本语法
postgresql数据库创建/修改/删除等写入类代码语法总结: 1,创建库 2,创建/删除表 2.1 创建表 create table myTableName 2.2 如果表不存在则创建表 crea ...
随机推荐
- java io系列12之 BufferedInputStream(缓冲输入流)的认知、源码和示例
本章内容包括3个部分:BufferedInputStream介绍,BufferedInputStream源码,以及BufferedInputStream使用示例. 转载请注明出处:http://www ...
- Linux记录-salt-minion安装
python -m SimpleHTTPServer 8888#!/bin/bash sed -i 's/^#//g' /etc/yum.repos.d/centos7.4.repo sed -i ' ...
- java-Array数组常用操作例子(基础必备)
package com.net.xinfang.reflect; import java.util.ArrayList; import java.util.Arrays; import java.ut ...
- Python复习笔记(五)面向对象
1. __init__方法 # 1. 为对象在内存 中分配空间 -- 创建对象 # 2. 为对象属性 设置初始值 -- 初始化方法(init)+-------------- # 3. __init__ ...
- SpringBoot系列: Actuator监控
Sprng Boot 2 actuator变动加大, 网上很多资料都都已经过期. ============================配置项============================ ...
- Excel列名序号互转
public static int ToIndex(string columnName) { if (!Regex.IsMatch(columnName.ToUpper(), @"[A-Z] ...
- linux连接工具隧道模式
使用linux连接工具,比如putty,xshell可以使用隧道模式跳转登录其他服务器 A->B B->C 比如正常情况下,A主机能访问B主机,B主机能访问C主机,那么就可以设置隧道模式让 ...
- ****** 三十 ******、软设笔记【计算机体系结构】-循环冗余校验码(CRC)
循环冗余校验码(CRC) 广泛地在网络通信及磁盘存储时采用. 1.多项式 在循环冗余校验(CRC)码中,无一例外地要提到多项式的概念.一个二进制数可以以一个多项式来表示.如1011表示为多项式X ...
- 深度理解PHP中for与foreach两个循环结构遍历数组的区别
遍历一个数组是编程中最常见不过的了,这里讨论下for和foreach两种方法: 首先,我们先准备两个用于遍历的数组: $arr1=array(1=>'a', 3=>22, 5=>'b ...
- 关于利用PHP访问MySql数据库的逻辑操作以及增删改查实例操作
PHP访问MySql数据库 <?php //造连接对象$db = new MySQLi("localhost","root","",& ...