美文网首页程序员
浅谈python上下文

浅谈python上下文

作者: Rokkia | 来源:发表于2017-02-06 16:17 被阅读1218次

    上下文在搞ios的时候就曾碰到过,但那时候并没有详细的了解,在python中看到后,有些忍不住了,于是看了几篇文章,过来做个总结.

    这里只不过是个总结,如果想要学习推荐这两篇文章,写的很详细
    http://blog.jobbole.com/64175/
    http://www.ibm.com/developerworks/cn/opensource/os-cn-pythonwith/#icomments 这一篇写的尤为详细

    有上面两篇文章在,我就不再做总结了.个人认为已经写的很详细了。这里只列举两篇文章中我认为重要的部分。

    1.with语法格式
    with context_expression [as target(s)]:
            with-body
    

    这里context_expression返回的是一个上下文管理器对象.这个对象已经满足了上下文协议,也就是说这个对象已经有了__exit__()与__enter__()方法,其中如果使用了as,那么将会将__enter__()方法返回的值赋值给target(s)

    2.with的执行流程

    这是我觉着第二篇文章的精华部分

        context_manager = context_expression
        exit = type(context_manager).__exit__  
        value = type(context_manager).__enter__(context_manager)
        exc = True   # True 表示正常执行,即便有异常也忽略;False 表示重新抛出异常,需要对异常进行处理
        try:
            try:
                target = value  # 如果使用了 as 子句
                with-body     # 执行 with-body
            except:
                # 执行过程中有异常发生
                exc = False
                # 如果 __exit__ 返回 True,则异常被忽略;如果返回 False,则重新抛出异常
                # 由外层代码对异常进行处理
                if not exit(context_manager, *sys.exc_info()):
                    raise
        finally:
            # 正常退出,或者通过 statement-body 中的 break/continue/return 语句退出
            # 或者忽略异常退出
            if exc:
                exit(context_manager, None, None, None) 
            # 缺省返回 None,None 在布尔上下文中看做是 False
    

    1.通过context_expression创建上下文管理器context_manager
    2.检查__exit__方法,检查__enter__方法,如果都设置exc为True标记正常执行。这里有两个很有意思的地方,1>如果标记为True表示即使有错误也继续执行.2>在with中会先检查是否有__exit__方法
    3.执行__enter__方法,如果with中有as则返回__enter__返回值
    4.执行with-body,也即是with的代码块
    5.这是核心步骤,通过代码我们也可以看出,不论有没有错误都会执行__exit__方法,却别就在于,如果没有异常,则以 None 作为参数调用 __exit__(None, None, None) .如果执行过程中出现异常,则使用 sys.exc_info 得到的异常信息为参数调用 __exit__(exc_type, exc_value, exc_traceback)
    6.出现异常时,如果 exit(type, value, traceback) 返回 False,则会重新抛出异常,让with 之外的语句逻辑来处理异常,这也是通用做法;如果返回 True,则忽略异常,不再对异常进行处理.

    3.自定义上下文管理器
    class DummyResource:
            def __init__(self, tag):
                self.tag = tag
                print 'Resource [%s]' % tag
            def __enter__(self):
                print '[Enter %s]: Allocate resource.' % self.tag
                return self   # 可以返回不同的对象
            def __exit__(self, exc_type, exc_value, exc_tb):
                print '[Exit %s]: Free resource.' % self.tag
                if exc_tb is None:
                    print '[Exit %s]: Exited without exception.' % self.tag
                else:
                    print '[Exit %s]: Exited with exception raised.' % self.tag
                    return False   # 可以省略,缺省的None也是被看做是False
    

    这个例子也很是经典。
    __enter__方法并没有什么要研究的
    关键在于__exit__方法
    首先,不管是否有异常需先释放资源,然后,通过with的执行流程我们知道,如果没有报错exc_type,exc_value,exc_tb都应该是None,于是在__exit__方法中判断exc_tb是否为None,如果为None则说明正确执行或者是忽略错误,由于with中exc默认为True所以无需返回,如果不为None则说明要抛出异常,需返回False.

    其实到这里就差不多算是了解上下文与with使用了.不过两篇文章都介绍了contextlib的使用.还是推荐各位看一下第二篇。

    写道这里大家可能会费解,为什么会推荐第一篇。因为我觉着第一篇有这么一句话写的很好。

    上下文管理器的任务是 —— 代码块执行前准备,代码块执行后收拾。

    感谢收看,欢迎拍砖

    相关文章

      网友评论

        本文标题:浅谈python上下文

        本文链接:https://www.haomeiwen.com/subject/yzfuittx.html