`
reb12345reb
  • 浏览: 47626 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

Python-With...As语法

 
阅读更多

理解Python中的with…as…语法

使用语言的好特性,而不是那些糟糕的特性————不知道谁说的

好久不学习python的语法了,上次去面试,和面试官聊到了python中的with-as statement(也称context manager),挺感兴趣的,这两天学习了一番,收获颇丰在此分享。

先说明一个常见问题,文件打开:

1
2
3
4
5
6
7
try:
    f = open('xxx')
    do something
except:
    do something
finally:
    f.close()

其实我个人不止一次在网上看到有这么写的了,这个是错的。
首先正确的如下:

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

很麻烦不是么,但正确的方法就是这么写。
我们为什么要写finally,是因为防止程序抛出异常最后不能关闭文件,但是需要关闭文件有一个前提就是文件已经打开了。
在第一段错误代码中,如果异常发生在f=open(‘xxx’)的时候,比如文件不存在,立马就可以知道执行f.close()是没有意义的。改正后的解决方案就是第二段代码。

好了言归正转,开始讨论with语法。

首先我们从下面这个问题谈起,try-finally的语法结构:

1
2
3
4
5
set things up
try:
    do something
finally:
    tear things down

这东西是个常见结构,比如文件打开,set things up就表示f=open('xxx')tear things down就表示f.close()。在比如像多线程锁,资源请求,最终都有一个释放的需求。Try…finally结构保证了tear things down这一段永远都会执行,即使上面do something得工作没有完全执行。

如果经常用这种结构,我们首先可以采取一个较为优雅的办法,封装!

1
2
3
4
5
6
7
8
9
10
11
def controlled_execution(callback):
    set things up
    try:
        callback(thing)
    finally:
        tear things down
 
def my_function(thing):
    do something
 
controlled_execution(my_function)

封装是一个支持代码重用的好办法,但是这个办法很dirty,特别是当do something中有修改一些local variables的时候(变成函数调用,少不了带来变量作用域上的麻烦)。

另一个办法是使用生成器,但是只需要生成一次数据,我们用for-in结构去调用他:

1
2
3
4
5
6
7
8
9
def controlled_execution():
    set things up
    try:
        yield thing
    finally:
        tear things down
         
for thing in controlled_execution():
    do something with thing

因为thing只有一个,所以yield语句只需要执行一次。当然,从代码可读性也就是优雅的角度来说这简直是糟糕透了。我们在确定for循环只执行一次的情况下依然使用了for循环,这代码给不知道的人看一定很难理解这里的循环是什么个道理。

最终的python-dev团队的解决方案。(python 2.5以后增加了with表达式的语法)

1
2
3
4
5
6
7
8
9
class controlled_execution:
    def __enter__(self):
        set things up
        return thing
    def __exit__(self, type, value, traceback):
        tear things down
         
with controlled_execution() as thing:
        do something

在这里,python使用了with-as的语法。当python执行这一句时,会调用__enter__函数,然后把该函数return的值传给as后指定的变量。之后,python会执行下面do something的语句块。最后不论在该语句块出现了什么异常,都会在离开时执行__exit__。
另外,__exit__除了用于tear things down,还可以进行异常的监控和处理,注意后几个参数。要跳过一个异常,只需要返回该函数True即可。下面的样例代码跳过了所有的TypeError,而让其他异常正常抛出。

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

在python2.5及以后,file对象已经写好了__enter__和__exit__函数,我们可以这样测试:

1
2
3
4
5
6
7
8
9
10
11
12
>>> f = open("x.txt")
>>> f
<open file 'x.txt', mode 'r' at 0x00AE82F0>
>>> f.__enter__()
<open file 'x.txt', mode 'r' at 0x00AE82F0>
>>> f.read(1)
'X'
>>> f.__exit__(None, None, None)
>>> f.read(1)
Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
ValueError: I/O operation on closed file

之后,我们如果要打开文件并保证最后关闭他,只需要这么做:

1
2
3
with open("x.txt") as f:
    data = f.read()
    do something with data

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

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

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

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

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

感谢以下参考资料:
stackoverflow: Catching an exception while using a Python ‘with’ statement
Understanding Python’s “with” statement
python docs:
http://docs.python.org/2/reference/compound_stmts.html#with
http://docs.python.org/2/reference/datamodel.html#context-managers
http://docs.python.org/2/library/contextlib.html#contextlib.nested

Tags : python
分享到:
评论

相关推荐

    Python基础语法.docx

    /usr/bin/python3 # -*- coding: UTF-8 -*- 2. 导入模块行 导入整个模块,格式: import module 导入模块中全部函数,格式为: from module import * 二、标识符 首字符必须是字母或下划线。 标识符对大小写敏感。 ...

    play框架手册

    @play.data.binding.As - 30 - @play.data.binding.NoBinding - 31 - play.data.binding.TypeBinder - 31 - @play.data.binding.Global - 32 - 结果类型 - 32 - 返回一些文本类型的内容 - 33 - 返回一个JSON字符串 -...

    play framework 框架手册 word 版

    @play.data.binding.As - 30 - @play.data.binding.NoBinding - 31 - play.data.binding.TypeBinder - 31 - @play.data.binding.Global - 32 - 结果类型 - 32 - 返回一些文本类型的内容 - 33 - 返回一个JSON字符串 -...

    Python 的 with 语句详解

    with是从Python 2.5 引入的一个新的语法,更准确的说,是一种上下文的管理协议,用于简化try…except…finally的处理流程。with通过__enter__方法初始化,然后在__exit__中做善后以及处理异常。对于一些需要预先设置...

    Python库参考手册.pdf

    至于Python 语言参考手册 则是该语言的语法和语义问题上的权威阐释. 最后 扩展或嵌入 Python 解释器 一文解说了如何在Python 中加入新的扩展模组; 以及怎样把Python 解释器嵌入到其他的应用程式中.

    Python with用法:自动关闭文件进程

    实际上,Python 提供了 with 语句来管理资源关闭。比如可以把打开的文件放在 with 语句中,这样 with 语句就会帮我们自动关闭文件。 with 语句的语法格式如下: with context expression [as target(s)]: with ...

    Python 中文手册

    Python 优雅的语法,动态类型,以及它天然的解释能力,使其成为了大多数平台上应用于各领域 理想的脚本语言以及开发环境。 The Python interpreter and the extensive standard library are freely available in ...

    Python学习笔记之读取文件、OS模块、异常处理、with as语法示例

    本文实例讲述了Python学习笔记之读取文件、OS模块、异常处理、with as语法。分享给大家供大家参考,具体如下: 文件读取 #读取文件 f = open(test.txt,r) print(f.read()) #打印文件内容 #关闭文件 f.close() 获取...

    Python中的with…as用法介绍

    这个语法是用来代替传统的try…finally语法的。 复制代码 代码如下: with EXPRESSION [ as VARIABLE] WITH-BLOCK 基本思想是with所求值的对象必须有一个__enter__()方法,一个__exit__()方法。 紧跟with后面的语句...

    Python参考手册

    that would otherwise be inaccessible to Python programmers, as well as modules written in Python that provide standardized solutions for many problems that occur in everyday programming. Some of these...

    Python最常见的170道面试题全解析答案(二).docx

    请写一个 Python 逻辑,计算一个文件中的大写字母数量 答: with open('A.txt') as fs: count = 0 for i in fs.read(): if i.isupper(): count += 1 print(count) 61. 请写一段 Python连接Mongo数据库,然后的...

    freemarker语法完整版

    Freemarker页面语法 A 概念 最常用的 3 个概念 sequence 序列,对应java 里的list 、数组等非键值对的集合 hash 键值对的集合 namespace 对一个ftl 文件的引用, 利用这个名字可以访问到该ftl 文件的资源 ...

    Python读取YAML文件过程详解

    这篇文章主要介绍了Python...with open('demo1.yaml', 'r', encoding='utf-8') as f: file_content = f.read() content = yaml.load(file_content, yaml.FullLoader) print(content) demo1.yaml - 123 # int - 3.1

    Python3.x和Python2.x的区别介绍

    1.性能Py3.0运行 pystone benchmark的速度比Py2.5慢30%。...=2)去除“,全部改用repr()3)关键词加入as 和with,还有True,False,None4)整型除法返回浮点数,要得到整型结果,请使用//5)加入nonl

    Python核心编程第二版

     10.4.1 with语句   10.4.2 *上下文管理协议   10.5 *字符串作为异常   10.6 触发异常   10.7 断言   10.8 标准异常   10.9 *创建异常   10.10 (现在)为什么用异常   10.11 到底为什么...

    Python核心编程(第二版).pdf (压缩包分2部分,第二部分)

    原书名: Core Python Programming (2nd Edition) 原出版社: Prentice Hall PTR 作者: (美)Wesley J. Chun 译者: 宋吉广 出版社:人民邮电出版社 ISBN:9787115178503 上架时间:2008-6-23 出版日期:2008 ...

    Python核心编程第二版(ok)

    Python核心编程第二版(ok) 第1部分 Python核心  第1章 欢迎来到Python世界   1.1 什么是Python   1.2 起源   1.3 特点   1.3.1 高级   1.3.2 面向对象   1.3.3 可升级   1.3.4 可扩展   ...

    Python核心编程(第二版).pdf (压缩包分2部分,第一部分)

    原书名: Core Python Programming (2nd Edition) 原出版社: Prentice Hall PTR 作者: (美)Wesley J. Chun 译者: 宋吉广 出版社:人民邮电出版社 ISBN:9787115178503 上架时间:2008-6-23 出版日期:2008 ...

    julia-1.1.0-win64

    Julia provides ease and expressiveness for high-level numerical computing, in the same way as languages such as R, MATLAB, and Python, but also supports general programming. To achieve this, Julia ...

Global site tag (gtag.js) - Google Analytics