用 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
...
with closing(urllib.request.urlopen('http://www.yahoo.com')) as f:
  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
...
with closing(urllib.request.urlopen('http://www.yahoo.com')) as f:
  for line in f:
    sys.stdout.write(line)

转载于:https://www.cnblogs.com/alan-babyblog/p/5153343.html

转载:简单介绍Python中的try和finally和with方法相关推荐

  1. python中len用法_简单介绍Python中的len()函数的使用

    简单介绍Python中的len()函数的使用 函数:len() 1:作用:返回字符串.列表.字典.元组等长度 2:语法:len(str) 3:参数:str:要计算的字符串.列表.字典.元组等 4:返回 ...

  2. 简述python中的几种数据类型,简单介绍Python中的几种数据类型

    简单介绍Python中的几种数据类型 python 里面分为 基本数据类型 和 复合数据类型 基本数据类型包括:数值 字符串 布尔 和 none 复合数据类型包括:列表 元组 字典 和集合怎么算是深情 ...

  3. python 外部参数过长_介绍python中slice参数过长的处理方法及实例

    python教程栏目介绍slice参数过长的处理方法 很多小伙伴对于slice参数的概念理解停留在概念上,切片的参数有三个,分别是step .start .stop .因为参数的值也是多变的,所以我们 ...

  4. 简单介绍Python中的几种数据类型

    大体上把Python中的数据类型分为如下几类: Number(数字) 包括int,long,float,complex String(字符串) 例如:hello,"hello",h ...

  5. 简单介绍Python中异常处理用法

    这篇文章主要给大家分享的是 Python中异常处理用法,为了保证程序的健壮性与容错性,即在遇到错误时候程序不会崩溃,我们需要对异常进行处理,下面来看看文章对此的用法,需要的朋友可以参考一下 为了保证程 ...

  6. len函数python返回值类型_简单介绍Python中的len()函数的使用

    01状态机介绍 游戏中的状态机一般都是有限状态机,简写为FSM(有限状态机),简称状态机,是表示有限个状态以及在这些状态之间的转移和动作等行为的数学模型. 状态机的每一个状态至少需要有以下三个操作: ...

  7. 简单介绍Python 中的迭代器和生成器

    可迭代对象和迭代器 迭代(iterate)意味着重复,就像 for 循环迭代序列和字典那样,但实际上也可使用 for 循环迭代其他对象:实现了方法 __iter__ 的对象(迭代器协议的基础). __ ...

  8. python中的json_简单介绍Python中的JSON使用

    JSON进阶 Python的dict对象可以直接序列化为JSON的{},不过,很多时候,我们更喜欢用class表示对象,比如定义Student类,然后序列化: import json class St ...

  9. python floor是什么意思_简单介绍Python中的floor()方法

    floor()方法返回不大于x的最大整数(向下取整). 语法 以下是floor()方法的语法: import math math.floor( x ) 注意:此函数是无法直接访问的,所以我们需要导入m ...

最新文章

  1. opencv 图像上画出目标运动的轨迹_基于opencv的单目和双目标定平台手眼标定
  2. Spring3 MVC Login Interceptor(Spring 拦截器)
  3. WM_PAINT介绍及OnPaint()函数的作用原理
  4. 传入一个MapString,Long 返回它按value排序后的结果
  5. Sass函数:random()函数
  6. [从架构到设计]第一回:设计,应该多一点
  7. 使用SQL编程创建100万条数据测试索引
  8. Python 语言程序设计(4-2)分支循环--无限循环
  9. Caused by: java.lang.NumberFormatException: For input string: 18446744073709551615
  10. 初学knockoutjs记录5——Computed observables依赖监控(2 Writable computed observables可写计算监控属性)...
  11. 好教程推荐系列:《计算机视觉--算法与应用》和《机器视觉算法与应用》等等
  12. 映象劫持使部分程序不可运行的解决方法
  13. cdr添加节点快捷键_coreldraw合并快捷键是什么,CDR合并快捷键是什么?
  14. linux 检测screen,linux screen编程,自动监控并向screen发送命令
  15. centos查看CPU温度
  16. 20.Consent Controller Get请求逻辑实现
  17. JQuery学习22篇(事件委托)
  18. 浅说ksm的适用范围
  19. CSS3-@keyframes动画
  20. 无线802.1x认证服务器,TP-Link无线路由器+Radius认证服务器实现无线终端802.1X认证...

热门文章

  1. ASP.NET里创建Microsoft Word文档
  2. [GraphQL] Create a GraphQL Schema
  3. BAT执行DOS命令查找本地浏览器
  4. 准备树莓派下的模块开发环境
  5. Inside dependency property
  6. android ArcGIS学习笔记一
  7. qt 消息处理机制与window消息处理机制的比较
  8. Xcode12快捷键配置
  9. oracle客户端安装后,oracle客户端安装
  10. rtmp测试地址_超详细搭建多码率测试环境(成为流媒体高手必经之路)