python的with用法

转自http://blog.kissdata.com/2014/05/23/python-with.html

With语句是什么?

有一些任务,可能事先需要设置,事后做清理工作。对于这种场景,Python的with语句提供了一种非常方便的处理方式。一个很好的例子是文件处理,你需要获取一个文件句柄,从文件中读取数据,然后关闭文件句柄。

如果不用with语句,代码如下:

  1. file = open("/tmp/foo.txt")
  2. data = file.read()
  3. file.close()

这里有两个问题:

  1. 一是可能忘记关闭文件句柄;
  2. 二是文件读取数据发生异常,没有进行任何处理。

下面是处理异常的加强版本:

  1. try:
  2. f = open(‘xxx‘)
  3. except:
  4. print ‘fail to open‘
  5. exit(-1)
  6. try:
  7. do something
  8. except:
  9. do something
  10. finally:
  11. f.close()

虽然这段代码运行良好,但是太冗长了。

这时候就是with一展身手的时候了。除了有更优雅的语法,with还可以很好的处理上下文环境产生的异常。

下面是with版本的代码:

  1. with open("/tmp/foo.txt") as file:
  2. data = file.read()

with如何工作?

  • 紧跟with后面的语句被求值后,返回对象的 __enter__() 方法被调用,这个方法的返回值将被赋值给as后面的变量。
  • 当with后面的代码块全部被执行完之后,将调用前面返回对象的 __exit__()方法。

下面例子可以具体说明with如何工作:

  1. #!/usr/bin/env python
  2. # with_example01.py
  3. class Sample:
  4. def __enter__(self):
  5. print "In __enter__()"
  6. return "Foo"
  7. def __exit__(self, type, value, trace):
  8. print "In __exit__()"
  9. def get_sample():
  10. return Sample()
  11. with get_sample() as sample:
  12. print "sample:", sample

运行代码,输出如下

  1. bash-3.2$ ./with_example01.py
  2. In __enter__()
  3. sample: Foo
  4. In __exit__()

正如你看到的: 1. __enter__()方法被执行 2. __enter__()方法返回的值 - 这个例子中是”Foo”,赋值给变量’sample’ 3. 执行代码块,打印变量”sample”的值为 “Foo” 4. __exit__()方法被调用 with真正强大之处是它可以处理异常。

可能你已经注意到Sample类的 __exit__ 方法有三个参数 val, type 和 trace。 这些参数在异常处理中相当有用。我们来改一下代码,看看具体如何工作的。

  1. #!/usr/bin/env python
  2. # with_example02.py
  3. class Sample:
  4. def __enter__(self):
  5. return self
  6. def __exit__(self, type, value, trace):
  7. print "type:", type
  8. print "value:", value
  9. print "trace:", trace
  10. def do_something(self):
  11. bar = 1/0
  12. return bar + 10
  13. with Sample() as sample:
  14. sample.do_something()

这个例子中,with后面的get_sample()变成了Sample()。这没有任何关系,只要紧跟with后面的语句所返回的对象有 __enter__() 和 __exit__() 方法即可。此例中,Sample()的 __enter__() 方法返回新创建的Sample对象,并赋值给变量sample。

代码执行后:

  1. bash-3.2$ ./with_example02.py
  2. type: <type ‘exceptions.ZeroDivisionError‘>
  3. value: integer division or modulo by zero
  4. trace: <traceback object at 0x1004a8128>
  5. Traceback (most recent call last):
  6. File "./with_example02.py", line 19, in <module>
  7. sample.do_something()
  8. File "./with_example02.py", line 15, in do_something
  9. bar = 1/0
  10. ZeroDivisionError: integer division or modulo by zero

实际上,在with后面的代码块抛出任何异常时,__exit__() 方法被执行。正如例子所示,异常抛出时,与之关联的type,value和stack trace传给 __exit__() 方法,因此抛出的ZeroDivisionError异常被打印出来了。开发库时,清理资源,关闭文件等等操作,都可以放在 __exit__ 方法当中。

另外,__exit__ 除了用于tear things down,还可以进行异常的监控和处理,注意后几个参数。要跳过一个异常,只需要返回该函数True即可。

下面的样例代码跳过了所有的TypeError,而让其他异常正常抛出。

  1. def __exit__(self, type, value, traceback):
  2. return isinstance(value, TypeError)

上文说了 __exit__ 函数可以进行部分异常的处理,如果我们不在这个函数中处理异常,他会正常抛出,这时候我们可以这样写(python 2.7及以上版本,之前的版本参考使用contextlib.nested这个库函数):

  1. try:
  2. with open( "a.txt" ) as f :
  3. do something
  4. except xxxError:
  5. do something about exception

总之,with-as表达式极大的简化了每次写finally的工作,这对保持代码的优雅性是有极大帮助的。

如果有多个项,我们可以这么写:

  1. with open("x.txt") as f1, open(‘xxx.txt‘) as f2:
  2. do something with f1,f2

因此,Python的with语句是提供一个有效的机制,让代码更简练,同时在异常产生时,清理工作更简单。

时间: 2024-10-02 02:04:23

python的with用法的相关文章

python &#160; __name__==&#39;__main__&#39; 用法

python 文件的后缀为.py,比如 name.py python 文件可以直接执行,也可以被导入.调用,比如import name; script 1: #!/bin/python # Filename:name.py if __name__=='__main__':     print 'This program is being run by itself' else:     print 'I am being imported from another module' script

python之函数用法capitalize()

# -*- coding: utf-8 -*- #python 27 #xiaodeng #python之函数用法capitalize() #capitalize() #说明:将字符串的第一个字母变成大写,其他字母变小写. ''' capitalize(...) S.capitalize() -> string Return a copy of the string S with only its first character capitalized. ''' #案例 str='xiaoden

python之函数用法setdefault()

# -*- coding: utf-8 -*- #python 27 #xiaodeng #python之函数用法setdefault() #D.get(k,d) #说明:k在D中,则返回 D[K],如果k不在D中,则返回d值 #D.get(k,d), also set D[k]=d if k not in D ''' >>> help(dict.setdefault) Help on built-in function setdefault: setdefault(...) D.set

python之函数用法islower()

# -*- coding: utf-8 -*- #python 27 #xiaodeng #python之函数用法islower() #http://www.runoob.com/python/att-string-islower.html #islower() #说明:检测字符串是否都由小写字母组成 str = "THIS is string example....wow!!!" print str.islower()#False str = "this is string

python之函数用法xrange()

# -*- coding: utf-8 -*- #python 27 #xiaodeng #python之函数用法xrange() #xrange() #说明:返回一个生成器 #xrange做循环的性能比range好,尤其是返回很大的时候.除非要返回一个列表,则用range. ''' class xrange(object) | xrange(stop) -> xrange object | xrange(start, stop[, step]) -> xrange object | | Li

python之函数用法startswith()

# -*- coding: utf-8 -*- #python 27 #xiaodeng #python之函数用法startswith() #http://www.runoob.com/python/att-string-startswith.html #startswith() #说明:返回布尔值,用于检查字符串是否是以指定子字符串开头,如果是则返回 True,否则返回 False. ''' startswith(...) S.startswith(prefix[, start[, end]]

python之函数用法globals()

# -*- coding: utf-8 -*- #python 27 #xiaodeng #python之函数用法globals() #globals() #说明:在当前作用域下,查看全局变量 ''' globals(...) globals() -> dictionary Return the dictionary containing the current scope's global variables. ''' #案例 b='xiaodeng' print globals#<buil

python之函数用法__setattr__

# -*- coding: utf-8 -*- #python 27 #xiaodeng #python之函数用法__setattr__ #http://www.cnblogs.com/hongfei/p/3858256.html #用__setattr__函数重构方法 class Fruit(): def __init__(self,color,price): self.__color = color self.__price = price def __setattr__(self,name

python之函数用法get()

# -*- coding: utf-8 -*- #python 27 #xiaodeng #python之函数用法get() #http://www.runoob.com/python/att-dictionary-get.html #dict.get(key, default=None) #说明:返回指定键的值,如果值不在字典中返回默认值. #key:要查找的键 #default:如果指定键的值不存在时,返回该默认值值 ''' >>> help(d.get) Help on built

python之函数用法fromkeys()

# -*- coding: utf-8 -*- #python 27 #xiaodeng #python之函数用法fromkeys() #fromkeys() #说明:用于创建一个新字典,以序列seq中元素做字典的键,value为字典所有键对应的初始值 ''' >>> help(dict.fromkeys) Help on built-in function fromkeys: fromkeys(...) dict.fromkeys(S[,v]) -> New dict with