用 Python 做一件很平常的事情: 打开文件, 逐行读入, 最后关掉文件; 进一步的需求是, 这也许是程序中一个可选的功能, 如果有任何问题, 比如文件无法打开, 或是读取出错, 那么在函数内需要捕获所有异常, 输出一行警告并退出. 代码可能一开始看起来是这样的
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 块外部, 如
def read_file(): f = open('azusa', 'r') try: print ''.join(f.readlines()) except: print 'error occurs while reading file' finally: f.close()
那么, 问题在于当打开文件失败, 抛出异常将不会被捕获.
挫一点的方法自然是, 再套一层 try 吧
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 结构来解决, 如
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 后引用的值. 一个简单的例子是
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!')
执行这一段代码, 输出将会是
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语句之前,先看看一段简单的代码吧
lock = threading.Lock() ... lock.acquire() elem = heapq.heappop(heap) lock.release()
很简单直观,多个线程共用一个优先级队列的时候,首先先用互斥锁lock.acquire()把优先级队列锁上,然后取元素,再然后lock.release()释放这个锁。
虽然看似非常符合逻辑的一个过程,但是里面隐藏着一个巨大的bug:当heap里面没有元素的时候,会抛出一个IndexError异常,再然后堆栈回滚,再然后lock.release()根本不会执行,这个锁就永远得不到释放,因此就发生了喜闻乐见的死锁问题。这个也是很多大神们讨厌异常的原因。经典Java风格的解决方案就是
lock = threading.Lock() ... lock.acquire() try: elem = heapq.heappop(heap) finally: lock.release()
这个虽然可以,但是怎么看怎么dirty,和Python优雅、简单的风格出入很大。其实,自从Python2.5开始引入了with语句,一切就变得非常简单:
lock = threading.Lock() ... with lock: elem = heapq.heappop(heap)
在此无论以何种方式离开with语句的代码块,锁都会被释放。
with语句的设计目的就是为了使得之前需要通过try...finally解决的清理资源问题变得简单、清晰,它的的用法是
with expression [as variable]: with-block
其中expression返回一个叫做「context manager」的对象,然后这个对象被赋给variable(如果有的话)。「context manager」对象有两个方法,分别是__enter__()和__exit__(),很明显一个在进入with-block时调用,一个离开with-block的时候调用。
这样的对象不需要自己去实现,在Python标准库里面很多API都是已经实现了这两个方法,最常见的一个例子就是读写文件的open语句。
with open('1.txt', encoding = 'utf-8') as fp: lines = fp.readlines()
无论是正常离开还是因为异常原因离开with语句块,打开的文件资源总是会释放。
接下去讨论一下with语句配合contextlib库的一些比较实用的方法,比如需要同时打开两个文件,一个读一个写,这个时候就可以这样写:
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也可以这样写:
from contextlib import closing ... with closing(urllib.request.urlopen('http://www.yahoo.com')) as f: for line in f: sys.stdout.write(line)
用 Python 做一件很平常的事情: 打开文件, 逐行读入, 最后关掉文件; 进一步的需求是, 这也许是程序中一个可选的功能, 如果有任何问题, 比如文件无法打开, 或是读取出错, 那么在函数内需要捕获所有异常, 输出一行警告并退出. 代码可能一开始看起来是这样的
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 块外部, 如
def read_file(): f = open('azusa', 'r') try: print ''.join(f.readlines()) except: print 'error occurs while reading file' finally: f.close()
那么, 问题在于当打开文件失败, 抛出异常将不会被捕获.
挫一点的方法自然是, 再套一层 try 吧
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 结构来解决, 如
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 后引用的值. 一个简单的例子是
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!')
执行这一段代码, 输出将会是
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语句之前,先看看一段简单的代码吧
lock = threading.Lock() ... lock.acquire() elem = heapq.heappop(heap) lock.release()
很简单直观,多个线程共用一个优先级队列的时候,首先先用互斥锁lock.acquire()把优先级队列锁上,然后取元素,再然后lock.release()释放这个锁。
虽然看似非常符合逻辑的一个过程,但是里面隐藏着一个巨大的bug:当heap里面没有元素的时候,会抛出一个IndexError异常,再然后堆栈回滚,再然后lock.release()根本不会执行,这个锁就永远得不到释放,因此就发生了喜闻乐见的死锁问题。这个也是很多大神们讨厌异常的原因。经典Java风格的解决方案就是
lock = threading.Lock() ... lock.acquire() try: elem = heapq.heappop(heap) finally: lock.release()
这个虽然可以,但是怎么看怎么dirty,和Python优雅、简单的风格出入很大。其实,自从Python2.5开始引入了with语句,一切就变得非常简单:
lock = threading.Lock() ... with lock: elem = heapq.heappop(heap)
在此无论以何种方式离开with语句的代码块,锁都会被释放。
with语句的设计目的就是为了使得之前需要通过try...finally解决的清理资源问题变得简单、清晰,它的的用法是
with expression [as variable]: with-block
其中expression返回一个叫做「context manager」的对象,然后这个对象被赋给variable(如果有的话)。「context manager」对象有两个方法,分别是__enter__()和__exit__(),很明显一个在进入with-block时调用,一个离开with-block的时候调用。
这样的对象不需要自己去实现,在Python标准库里面很多API都是已经实现了这两个方法,最常见的一个例子就是读写文件的open语句。
with open('1.txt', encoding = 'utf-8') as fp: lines = fp.readlines()
无论是正常离开还是因为异常原因离开with语句块,打开的文件资源总是会释放。
接下去讨论一下with语句配合contextlib库的一些比较实用的方法,比如需要同时打开两个文件,一个读一个写,这个时候就可以这样写:
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也可以这样写:
from contextlib import closing ... with closing(urllib.request.urlopen('http://www.yahoo.com')) as f: for line in f: sys.stdout.write(line)
本文向大家介绍简单介绍Python中的round()方法,包括了简单介绍Python中的round()方法的使用技巧和注意事项,需要的朋友参考一下 round()方法返回 x 的小数点四舍五入到n个数字。 语法 以下是round()方法的语法: 参数 x --这是一个数值表达式 n --这也是一个数值表达式 返回值 该方法返回 x 的小数点四舍五入到n个数字 例子 下面的例子显示
本文向大家介绍简单介绍区分applet和application的方法,包括了简单介绍区分applet和application的方法的使用技巧和注意事项,需要的朋友参考一下 Java语言是一种半编译半解释的语言。Java的用户程序分为两类:Java Application和Java Applet。这两类程序在组成结构和执行机制上都有一定的差异: Application 1.appli
本文向大家介绍简单介绍Python中的filter和lambda函数的使用,包括了简单介绍Python中的filter和lambda函数的使用的使用技巧和注意事项,需要的朋友参考一下 filter(function or None, sequence),其中sequence 可以是list ,tuple,string。这个函数的功能是过滤出sequence 中所有以元素自身作... filter(
Python 异常处理机制还提供了一个 finally 语句,通常用来为 try 块中的程序做扫尾清理工作。 注意,和 else 语句不同,finally 只要求和 try 搭配使用,而至于该结构中是否包含 except 以及 else,对于 finally 不是必须的(else 必须和 try except 搭配使用)。 在整个异常处理机制中, finally 语句的功能是:无论 try 块是否
本文向大家介绍Android Retrofit的简单介绍和使用,包括了Android Retrofit的简单介绍和使用的使用技巧和注意事项,需要的朋友参考一下 Retrofit与okhttp共同出自于Square公司,retrofit就是对okhttp做了一层封装。把网络请求都交给给了Okhttp,我们只需要通过简单的配置就能使用retrofit来进行网络请求了,其主要作者是Android大神Ja
本文向大家介绍C# FileStream简单介绍和使用,包括了C# FileStream简单介绍和使用的使用技巧和注意事项,需要的朋友参考一下 本章讲述:FileStream类的基本功能,以及简单示例; 1、引用命名空间:using System.IO; 2、注意:使用IO操作文件时,要注意流关闭和释放问题! 强力推荐:将创建文件流对象的过程写在using当中,会自动帮助我们释放资源; 使用try