Pure Soul

  1. 首页
  2. python
  3. 正文

python上下文管理

2021年11月4日 583点热度 0人点赞 0条评论

什么是上下文管理

with open('text.txt','r') as f:
    lines=f.readlines()

打开文件的with操作是代码中很常见的操作,这就是一个简单的上下文管理,而with open('text.txt','r') as f就是上下文表达式;其中open('text.txt','r')是上下文管理器,f为资源对象(说白了就是一个实例化的类)。

如何实现上下文管理器

上下文管理器是基于上下文管理协议锁生成的,其中最重要的上下文管理协议就是__enter__()以及__exit__()方法,分别表示获取资源或之前应当完成的动作,以及释放资源之后的动作。如果需要自己实现一个上下文管理器,那么一定要实现__enter__()以及__exit__()方法

class MyContexManager:
    def __init__(self, name):
        self.name=name
    def __enter__(self):
        print('Context name is', self.name)
        print('-'*50)
        for i in range(3):
            print('|'+' '*48+'|')
        print('|'+' '*23+'^_^'+' '*22+'|')
        for i in range(3):
            print('|'+' '*48+'|')
        print('-' * 50)
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        print(exc_type, exc_val, exc_tb)
        print('Exit!')
        return True

    def contexMethod(self, *args, **kwargs):
        print(args, kwargs)

with MyContexManager('dsa') as m:
    print(type(m))
    m.contexMethod('print',' hello')

最终的运行结果

Context name is dsa
--------------------------------------------------
|                                                |
|                                                |
|                                                |
|                       ^_^                      |
|                                                |
|                                                |
|                                                |
--------------------------------------------------
<class '__main__.MyContexManager'>
('print', ' hello') {}
None None None
Exit!

当代码没有跑出错误的时候,上下文管理器相当于以下执行顺序:

m=MyContexManager('dsa')
m.__enter__()
m.contexMethod()
m.__exit__(None, None, None)

然而,当上下文管理器的主题发生错误之后,会将exception type,exception value,exception traceback三个关键参数传入__exit__(),进行错误处理。如果错误正常处理了,则在__exit__()返回True,否则返回False。这也就可以看出,资源管理器除了更加便捷优雅的操作资源外,还有一个大作用就是优雅的处理出现的错误。

如果在主要的逻辑代码当中出现大量的try...except...的代码,势必会影响可读性,因而在__exit__()当中处理会显得更为美观。当在__exit__()中处理了错误之后并返回True,不会再抛出错误。

class MyContexManager:
    def __init__(self, name):
        self.name=name
    def __enter__(self):
        print('Context name is', self.name)
        print('-'*50)
        for i in range(3):
            print('|'+' '*48+'|')
        print('|'+' '*23+'^_^'+' '*22+'|')
        for i in range(3):
            print('|'+' '*48+'|')
        print('-' * 50)
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        if exc_type is ZeroDivisionError:
            print('Zero division error')
            return True
        # print(exc_type, exc_val, exc_tb)
        print('Exit!')

    def contexMethod(self, *args, **kwargs):
        print(1/0)
        print(args, kwargs)

with MyContexManager('dsa') as m:
    print(type(m))
    m.contexMethod('print',' hello')

使用contextlib实现下文管理器

使用contextlib当中的contextmanager对函数进行装饰可以快速构建一个上下文管理器,而不需要自己手动繁杂的实现一个类。但是contextmanager装饰的函数必须包含yield关键字,其实也就是装饰了一个生成器。

import contextlib

@contextlib.contextmanager
def open_func(file_name):
    # __enter__方法
    print('open file:', file_name, 'in __enter__')
    file_handler = open(file_name, 'r')
    # 【重点】:yield
    yield file_handler
    # __exit__方法
    print('close file:', file_name, 'in __exit__')
    file_handler.close()
    return

with open_func('/Users/MING/mytest.txt') as file_in:
    for line in file_in:
        print(line)

在被装饰的生成器中(带有yield),而yield之前的代码,就相当于__enter__里的内容。yield之后的代码,就相当于__exit__里的内容。如果需要在装饰器当中捕捉错误,那么可以将yield包装在try当中。

from contextlib import contextmanager

def FileRename(filename: str):
    import shutil
    base,root=filename.split('.')
    shutil.copy(filename, base+'_copy.'+root)
    return open(base+'_copy.'+root)

@contextmanager
def manager(filename=None)->str:
    print('rename')
    res=FileRename(filename)
    try:
        yield res.readline()
    except Exception as ex:
        print('There is error ', ex.__str__())
    finally:
        print('-----finally-----')

with manager('text.txt') as m:
    z=1/0
    print(m)
标签: 暂无
最后更新:2021年11月4日

ycq

这个人很懒,什么都没留下

点赞
下一篇 >

COPYRIGHT © 2021 oo2ee.com. ALL RIGHTS RESERVED.

THEME KRATOS MADE BY VTROIS