zoukankan      html  css  js  c++  java
  • Python tricks(4) -- with statement

    简介

    with是从2.5版本引入的一个语法. 这个语法本身是为了解决try..finally繁琐的释放各类资源(文件句柄, Lock等)的问题.

    如果想在旧版本中使用这个功能, 直接引入future模块就可以.

    from __future__ import with_statement
    

    举例简单说明一下没有with和有with的代码区别

    try:
        dict_file = open("dict_file_path")
        for line in dict_file:
            print line,  # do something
    finally:
        dict_file.close()
    

    用with-statement的方式如下

    with open("dict_file_path") as dict_file:
        for line in dict_file:
            print line,  # do something
    

    明显使用了with之后语法更加简洁.

    官方对于with-statement的定义如下

    with_stmt ::=  "with" with_item ("," with_item)* ":" suite
    with_item ::=  expression ["as" target]
    

    从定义中, 我们可以看出, 如果想通过with使用多个资源的话, 可以使用下面的写法

    with open("d1_file") as d1, open("d2_file") as d2:
    

    as部分是可有可无的, 对于lock等这类资源来说一般都是这种用法

    个人认为, with-statement是现在带有内存管理语言的折中处理方法, 对于c++来说, 可以使用RAII的方式, 一个类有明确的析构函数, 在超出作用域之后会被调用, 在析构函数内进行资源的释放是非常不错的选择. 也体现了c++的高效, 灵活和优雅.

    Java, python这类语言都无法做到, 但是语言自身的异常机制都非常完善, 不像c++为了兼容c导致异常机制显得有点鸡肋. try..catch..finally就成为了这类语言用来进行资源释放的方式, GC(垃圾回收)回收内存的时间不确定, 无法利用RAII.

    With-statement Magic Method

    python语言层面上对于with的支持是通过magic method来实现的, 和一般的python特性一样.

    使用PEP343中with-statement的定义来引入这两个magic method

    with VAR = EXPR:
            BLOCK
    

    直接翻译过来就是

    VAR = EXPR
    VAR.__enter__()
    try:
            BLOCK
    finally:
            VAR.__exit__()
    

    我们可以清楚的看到这两个magic method分别是__enter__和__exit__, 一个在进入with-statement block的时候初始化, 一个在离开的时候进行cleanup工作.

    下面来举一个简单的timer例子.

    import time
    
    class Timer(object):
        def __init__(self):
            pass
    
        def __enter__(self):
            self.start = time.time()
    
        def __exit__(self, exception_type, exception_val, trace):
            print "elapsed:", time.time() - self.start
    
    if __name__ == "__main__":
        with Timer():
            [i for i in xrange(10000000)]
    

    运行结果如下:

    elapsed: 1.32907581329
    

    timer是一个简单实用的类, 在编写性能测试代码的时候, 经常会用到.

    水平有限, 欢迎拍砖!

    2014.4.19 添加一个with带有异常处理的demo

     以一个操作数据库的session为例, 下面的方式可以替代繁琐的try...except...finally语句, 可以包装sqlalchemy的session.

    笔者用这个简单的封装作为sqlalchemy来方便处理session相关的操作. commit操作需要自己去调用, 也可以加入到exit方法中.

    class Wrapper(object):
        '''A context manager to automatically close an object with a close method
        in a with statement.'''
    
        def __init__(self, obj):
            self.obj = obj
    
        def __enter__(self):
            return self.obj  # bound to target
    
        def __exit__(self, exception_type, exception_val, trace):
            if exception_type:
                try:
                    self.obj.rollback()
                except AttributeError:  # obj cannot rollback
                    return True  # exception handled successfully
            try:
                self.obj.close()
            except AttributeError:  # obj isn't closable
                return True  # exception handled successfully    
    

      

    参考文献:

    1. PEP343: http://www.python.org/dev/peps/pep-0343/
    2. Python Docs <Compound statements>: http://docs.python.org/2/reference/compound_stmts.html#the-with-statement
  • 相关阅读:
    今天看到的一些好文语句摘录
    laravel5 怎么获取数组形式的数据
    laravel5.4将excel表格中的信息导入到数据库中
    phpmax_execution_time
    laravel 5.4 导出excel表格
    使用php函数ini_set()重新设置某个配置的设置值
    艾伟_转载:VS.NET 2010 新功能 [整理] 狼人:
    艾伟_转载:[一步一步MVC]第五回:让TagBuilder丰富你的HtmlHelper 狼人:
    艾伟_转载:.NET 4.0中数组的新增功能 狼人:
    艾伟_转载:一个简单的 Generic Factory 类 狼人:
  • 原文地址:https://www.cnblogs.com/icejoywoo/p/3533556.html
Copyright © 2011-2022 走看看