转载:简单介绍Python中的try和finally和with方法
用 Python 做一件很平常的事情: 打开文件, 逐行读入, 最后关掉文件; 进一步的需求是, 这也许是程序中一个可选的功能, 如果有任何问题, 比如文件无法打开, 或是读取出错, 那么在函数内需要捕获所有异常, 输出一行警告并退出. 代码可能一开始看起来是这样的
1
2
3
4
5
6
7
8
|
def read_file(): try : f = open ( 'yui' , 'r' ) print ''.join(f.readlines()) except : print 'error occurs while reading file' finally : f.close() |
不过这显然无法运作, 因为 f 是在 try 块中定义的, 而在 finally 中无法引用.
如果将 f 提取到 try 块外部, 如
1
2
3
4
5
6
7
8
|
def read_file(): f = open ( 'azusa' , 'r' ) try : print ''.join(f.readlines()) except : print 'error occurs while reading file' finally : f.close() |
那么, 问题在于当打开文件失败, 抛出异常将不会被捕获.
挫一点的方法自然是, 再套一层 try 吧
1
2
3
4
5
6
7
8
9
10
11
|
def read_file(): try : f = open ( 'sawako' , 'r' ) try : print ''.join(f.readlines()) except : print 'error occurs while reading file' finally : f.close() except : print 'error occurs while reading file' |
当然这不仅仅是多一层缩进挫了, 连警告输出都白白多一次呢.
正规一点的方式是, 使用 Python 引入的 with 结构来解决, 如
1
2
3
4
5
6
|
def readFile(): try : with open ( 'mio' , 'r' ) as f: print ''.join(f.readlines()) except : print 'error occurs while reading file' |
当文件打开失败时, 异常自然会被 except 到; 否则, 在 with 块结束之后, 打开的文件将自动关闭.
除了打开文件, 还有其它这样可以用于 with 的东西么? 或者说, 怎么自定义一个什么东西, 让它能用于 with 呢?
直接回答后一个问题吧, 秘密在于 Python 虚拟机在 with 块退出时会去寻找对象的 __exit__ 方法并调用它, 把释放资源的动作放在这个 __exit__ 函数中就可以了; 另外, 对象还需要一个 __enter__ 函数, 当进入 with 块时, 这个函数被调用, 而它的返回值将作为 as 后引用的值. 一个简单的例子是
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
class Test: def __init__( self ): print 'init' def __enter__( self ): print 'enter' return self def __exit__( self , except_type, except_obj, tb): print except_type print except_obj import traceback print ''.join(traceback.format_tb(tb)) print 'exit' return True with Test() as t: raise ValueError( 'kon!' ) |
执行这一段代码, 输出将会是
1
2
3
4
5
6
7
8
|
init enter < type 'exceptions.ValueError' > kon! File "test.py" , line 17 , in <module> raise ValueError( 'kon!' ) exit |
__exit__ 函数接受三个参数, 分别是异常对象类型, 异常对象和调用栈. 如果 with 块正常退出, 那么这些参数将都是 None . 返回 True 表示发生的异常已被处理, 不再继续向外抛出.
简单的介绍到此为止, 详细的情况可以参考 PEP 343 (这数字真不错, 7 3 ).
下面介绍下 with 语句的实例用法 & 高级用法:
Python高端、大气、上档次的with语句
在说with语句之前,先看看一段简单的代码吧
1
2
3
4
5
|
lock = threading.Lock() ... lock.acquire() elem = heapq.heappop(heap) lock.release() |
很简单直观,多个线程共用一个优先级队列的时候,首先先用互斥锁lock.acquire()把优先级队列锁上,然后取元素,再然后lock.release()释放这个锁。
虽然看似非常符合逻辑的一个过程,但是里面隐藏着一个巨大的bug:当heap里面没有元素的时候,会抛出一个IndexError异常,再然后堆栈回滚,再然后lock.release()根本不会执行,这个锁就永远得不到释放,因此就发生了喜闻乐见的死锁问题。这个也是很多大神们讨厌异常的原因。经典Java风格的解决方案就是
1
2
3
4
5
6
7
|
lock = threading.Lock() ... lock.acquire() try : elem = heapq.heappop(heap) finally : lock.release() |
这个虽然可以,但是怎么看怎么dirty,和Python优雅、简单的风格出入很大。其实,自从Python2.5开始引入了with语句,一切就变得非常简单:
1
2
3
4
|
lock = threading.Lock() ... with lock: elem = heapq.heappop(heap) |
在此无论以何种方式离开with语句的代码块,锁都会被释放。
with语句的设计目的就是为了使得之前需要通过try...finally解决的清理资源问题变得简单、清晰,它的的用法是
1
2
|
with expression [as variable]: with - block |
其中expression返回一个叫做「context manager」的对象,然后这个对象被赋给variable(如果有的话)。「context manager」对象有两个方法,分别是__enter__()和__exit__(),很明显一个在进入with-block时调用,一个离开with-block的时候调用。
这样的对象不需要自己去实现,在Python标准库里面很多API都是已经实现了这两个方法,最常见的一个例子就是读写文件的open语句。
1
2
|
with open ( '1.txt' , encoding = 'utf-8' ) as fp: lines = fp.readlines() |
无论是正常离开还是因为异常原因离开with语句块,打开的文件资源总是会释放。
接下去讨论一下with语句配合contextlib库的一些比较实用的方法,比如需要同时打开两个文件,一个读一个写,这个时候就可以这样写:
1
2
3
4
|
from contextlib import nested ... with nested( open ( 'in.txt' ), open ( 'out.txt' , 'w' )) as (fp_in, fp_out): ... |
这样就可以省掉两个with的语句的嵌套了,另外如果遇到一些还没有支持「context manager」的API呢?比如urllib.request.urlopen(),这个返回的对象因为不是「context manager」,结束的时候还需要自己去调用close方法。
类似这种API,contextlib提供了一个叫做closing方法,它会在离开with语句的时候,自动调用对象的close方法,因此urlopen也可以这样写:
1
2
3
4
5
|
from contextlib import closing ... for line in f: sys.stdout.write(line) |
用 Python 做一件很平常的事情: 打开文件, 逐行读入, 最后关掉文件; 进一步的需求是, 这也许是程序中一个可选的功能, 如果有任何问题, 比如文件无法打开, 或是读取出错, 那么在函数内需要捕获所有异常, 输出一行警告并退出. 代码可能一开始看起来是这样的
1
2
3
4
5
6
7
8
|
def read_file(): try : f = open ( 'yui' , 'r' ) print ''.join(f.readlines()) except : print 'error occurs while reading file' finally : f.close() |
不过这显然无法运作, 因为 f 是在 try 块中定义的, 而在 finally 中无法引用.
如果将 f 提取到 try 块外部, 如
1
2
3
4
5
6
7
8
|
def read_file(): f = open ( 'azusa' , 'r' ) try : print ''.join(f.readlines()) except : print 'error occurs while reading file' finally : f.close() |
那么, 问题在于当打开文件失败, 抛出异常将不会被捕获.
挫一点的方法自然是, 再套一层 try 吧
1
2
3
4
5
6
7
8
9
10
11
|
def read_file(): try : f = open ( 'sawako' , 'r' ) try : print ''.join(f.readlines()) except : print 'error occurs while reading file' finally : f.close() except : print 'error occurs while reading file' |
当然这不仅仅是多一层缩进挫了, 连警告输出都白白多一次呢.
正规一点的方式是, 使用 Python 引入的 with 结构来解决, 如
1
2
3
4
5
6
|
def readFile(): try : with open ( 'mio' , 'r' ) as f: print ''.join(f.readlines()) except : print 'error occurs while reading file' |
当文件打开失败时, 异常自然会被 except 到; 否则, 在 with 块结束之后, 打开的文件将自动关闭.
除了打开文件, 还有其它这样可以用于 with 的东西么? 或者说, 怎么自定义一个什么东西, 让它能用于 with 呢?
直接回答后一个问题吧, 秘密在于 Python 虚拟机在 with 块退出时会去寻找对象的 __exit__ 方法并调用它, 把释放资源的动作放在这个 __exit__ 函数中就可以了; 另外, 对象还需要一个 __enter__ 函数, 当进入 with 块时, 这个函数被调用, 而它的返回值将作为 as 后引用的值. 一个简单的例子是
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
class Test: def __init__( self ): print 'init' def __enter__( self ): print 'enter' return self def __exit__( self , except_type, except_obj, tb): print except_type print except_obj import traceback print ''.join(traceback.format_tb(tb)) print 'exit' return True with Test() as t: raise ValueError( 'kon!' ) |
执行这一段代码, 输出将会是
1
2
3
4
5
6
7
8
|
init enter < type 'exceptions.ValueError' > kon! File "test.py" , line 17 , in <module> raise ValueError( 'kon!' ) exit |
__exit__ 函数接受三个参数, 分别是异常对象类型, 异常对象和调用栈. 如果 with 块正常退出, 那么这些参数将都是 None . 返回 True 表示发生的异常已被处理, 不再继续向外抛出.
简单的介绍到此为止, 详细的情况可以参考 PEP 343 (这数字真不错, 7 3 ).
下面介绍下 with 语句的实例用法 & 高级用法:
Python高端、大气、上档次的with语句
在说with语句之前,先看看一段简单的代码吧
1
2
3
4
5
|
lock = threading.Lock() ... lock.acquire() elem = heapq.heappop(heap) lock.release() |
很简单直观,多个线程共用一个优先级队列的时候,首先先用互斥锁lock.acquire()把优先级队列锁上,然后取元素,再然后lock.release()释放这个锁。
虽然看似非常符合逻辑的一个过程,但是里面隐藏着一个巨大的bug:当heap里面没有元素的时候,会抛出一个IndexError异常,再然后堆栈回滚,再然后lock.release()根本不会执行,这个锁就永远得不到释放,因此就发生了喜闻乐见的死锁问题。这个也是很多大神们讨厌异常的原因。经典Java风格的解决方案就是
1
2
3
4
5
6
7
|
lock = threading.Lock() ... lock.acquire() try : elem = heapq.heappop(heap) finally : lock.release() |
这个虽然可以,但是怎么看怎么dirty,和Python优雅、简单的风格出入很大。其实,自从Python2.5开始引入了with语句,一切就变得非常简单:
1
2
3
4
|
lock = threading.Lock() ... with lock: elem = heapq.heappop(heap) |
在此无论以何种方式离开with语句的代码块,锁都会被释放。
with语句的设计目的就是为了使得之前需要通过try...finally解决的清理资源问题变得简单、清晰,它的的用法是
1
2
|
with expression [as variable]: with - block |
其中expression返回一个叫做「context manager」的对象,然后这个对象被赋给variable(如果有的话)。「context manager」对象有两个方法,分别是__enter__()和__exit__(),很明显一个在进入with-block时调用,一个离开with-block的时候调用。
这样的对象不需要自己去实现,在Python标准库里面很多API都是已经实现了这两个方法,最常见的一个例子就是读写文件的open语句。
1
2
|
with open ( '1.txt' , encoding = 'utf-8' ) as fp: lines = fp.readlines() |
无论是正常离开还是因为异常原因离开with语句块,打开的文件资源总是会释放。
接下去讨论一下with语句配合contextlib库的一些比较实用的方法,比如需要同时打开两个文件,一个读一个写,这个时候就可以这样写:
1
2
3
4
|
from contextlib import nested ... with nested( open ( 'in.txt' ), open ( 'out.txt' , 'w' )) as (fp_in, fp_out): ... |
这样就可以省掉两个with的语句的嵌套了,另外如果遇到一些还没有支持「context manager」的API呢?比如urllib.request.urlopen(),这个返回的对象因为不是「context manager」,结束的时候还需要自己去调用close方法。
类似这种API,contextlib提供了一个叫做closing方法,它会在离开with语句的时候,自动调用对象的close方法,因此urlopen也可以这样写:
1
2
3
4
5
|
from contextlib import closing ... for line in f: sys.stdout.write(line) |
转载:简单介绍Python中的try和finally和with方法的更多相关文章
- 【转载】关于Python中的yield
在介绍yield前有必要先说明下Python中的迭代器(iterator)和生成器(constructor). 一.迭代器(iterator) 在Python中,for循环可以用于Python中的任何 ...
- python中执行shell命令的几个方法小结(转载)
转载:http://www.jb51.net/article/55327.htm python中执行shell命令的几个方法小结 投稿:junjie 字体:[增加 减小] 类型:转载 时间:2014- ...
- 简单说明Python中的装饰器的用法
简单说明Python中的装饰器的用法 这篇文章主要简单说明了Python中的装饰器的用法,装饰器在Python的进阶学习中非常重要,示例代码基于Python2.x,需要的朋友可以参考下 装饰器对与 ...
- 简单谈谈Python中的几种常见的数据类型
简单谈谈Python中的几种常见的数据类型 计算机顾名思义就是可以做数学计算的机器,因此,计算机程序理所当然地可以处理各种数值.但是,计算机能处理的远不止数值,还可以处理文本.图形.音频.视频.网页等 ...
- Python中执行系统命令常见的几种方法--转载
Python中执行系统命令常见的几种方法 Python中执行系统命令常见的几种方法有: (1)os.system # 仅仅在一个子终端运行系统命令,而不能获取命令执行后的返回信息 # 如果再命令行下执 ...
- Python中使用多进程来实现并行处理的方法小结
进程和线程是计算机软件领域里很重要的概念,进程和线程有区别,也有着密切的联系,先来辨析一下这两个概念: 1.定义 进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和 ...
- python中readline判断文件读取结束的方法
注:内容来自网络 本文实例讲述了python中readline判断文件读取结束的方法.分享给大家供大家参考.具体分析如下: 大家知道,python中按行读取文件可以使用readline函数,下面现介绍 ...
- Python中转换角度为弧度的radians()方法
Python中转换角度为弧度的radians()方法 这篇文章主要介绍了Python中转换角度为弧度的radians()方法,是Python入门中的基础知识,需要的朋友可以参考下 radians()方 ...
- Python中日期和时间格式化输出的方法
本文转自:https://www.jb51.net/article/62518.htm 本文实例总结了python中日期和时间格式化输出的方法.分享给大家供大家参考.具体分析如下: python格式化 ...
随机推荐
- android仿win8 metro磁贴布局
代码下载 //更新代码, 这里是更新后的代码 //////////////////////// 1,含一个图片无限滚动的控件,自己实现的 2.可新增删除每个磁贴 3.来个图片吧 ////* ...
- 安装linux系统并配置那点事
安装完成后,将看到如下控制台: 输入以上安装信息中所填写的用户名(user),随后输入密码(user),即可登录 Ubuntu. 随时可使用 Ctrl + Alt 快捷键可离开虚拟机. 3 配置 Ub ...
- libgo 2.0发布
libgo 是一个使用 C++ 编写的协作式调度的stackful协程库, 同时也是一个强大的并行编程库. 设计之初是为高并发分布式Linux服务端程序开发提供底层框架支持,可以让链接进程序的同步的第 ...
- 剑指 offer set 4 矩形覆盖
总结 1. 斐波那契数列的变形题, 但是稍有隐晦, 有点意思 2. 求解 f(3) 时, 最后一块矩形可以竖着放, 也可以两块矩形横着放, 分别对应于 f(2) 和 f(1) ------------ ...
- linux modprobe命令参数及用法详解--linux加载模块命令
转:http://www.linuxso.com/command/modprobe.html modprobe(module probe) 功能说明:自动处理可载入模块. 语 法:modprobe [ ...
- 关于MFC库和CRT库冲突的分析
当MFC库和CRT库冲突时,会出现一个LNK2005的错误.具体的错误如下: nafxcwd.lib(dllmodul.obj): error LNK2005: _DllMain@12 already ...
- 1.7.6 Highlighting-高亮
1 高亮 solr的高亮允许匹配用户查询的文档的片段包含在查询响应中返回,高亮包含在返回结果的单独部分(highlighting部分). solr提供了一个高亮工具的集合,这个工具允许控制大量字段的片 ...
- 基于 Equinox 的 OSGi Console 的研究和探索
自定制 OSGi Console 进行组建和服务生命周期管理模块化编程的好处已经很好地被理解了约 40 年,但在 OSGi 之前,开发人员不得不自己发明模块化设计和系统.随着软件应用体系结构的不断发展 ...
- nodejs学习第一天
//按照nodejs文档上第一页的例子敲了一遍运行了 迷茫 先这样吧 慢慢来 const http = require('http'); const host = '127.0.0.1'; const ...
- oracle数据操纵语言(DML)data manipulation language(续集)
SQL查询语句(SELECT)进阶分组函数(Group Functions):对多行进行操作,并为每一组给出一个结果. AVG([DISTINCT|ALL] expression) 平均值COUNT ...