python 上下文管理器

python的上下文管理器看了很多解释

vamei的python教程

上下文管理器(context manager)是Python2.5开始支持的一种语法,用于规定某个对象的使用范围。一旦进入或者离开该使用范围,会有特殊操作被调用 (比如为对象分配或者释放内存)。它的语法形式是with...as...

 

python编程时光

1. 上下文表达式:with open('test.txt') as f:

2. 上下文管理器:open('test.txt')

3. f 不是上下文管理器,应该是资源对象。

 

个人理解是对资源的一些操作!

上下文管理器的实现有两种方式,我用1/0这个例子来展示一下


第一种方式:

"""
一个类实现了 __enter__和__exit__的方法,这个类的实例就是一个上下文管理器
"""

import traceback

class Resource():
    def __enter__(self):
        """
        我们可以将一些资源初始化动作放在 __enter__ 
        比如:数据库连接,打开文件
        一般返回资源对象
        """
        print('=== __enter__ ===')
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        """
         __exit__ 包含三个参数:
        exc_type 异常类型
        exc_val 异常值
        exc_tb 异常的错误栈信息
        当没有异常时三个都是None
        __exit__ 包含了异常捕捉和结束动作
        """
        print(exc_type, exc_val, traceback.print_tb(exc_tb))
        print('==== __exit__ ====')
        return True

    def zero_func(self, x):
        print(1/x)

with Resource() as res:
    """
    as 会把 __enter__ 返回值赋给 目标 res
    如果我们让 __enter__ return 1,在这里我们print(res),会发现res的值是1,
    如果我们在这里print(res),会发现先执行 __enter__ 再 执行__exit__
    """
    res.zero_func(0)
    """
    1/0 原本是会报错的,
    但是这里如果没有在 __exit__ 打印错误信息的话,这里是不会有异常信息的
    """

 

第二种方式:

"""
通过contextlib 创建上下文管理器
"""

import traceback
import contextlib

# 使用修饰器 @contextlib.contextmanager
@contextlib.contextmanager
def zero_func(x):
    # yield 之前的 都相当于 __enter__ 的内容
    print('====== __enter__ =========')

    try:
        """
        yield 后面可以返回一个对象,相当于 __enter__ 的return
        """
        yield
        """
        yield 后面的内容相当于__exit__
        """
        zero_parameter = 1/x
    except Exception as exc:
        # 处理异常
        """
        如果使用traceback.print_exc()会返回一个空对象
        错误信息的打印有可能出现在__exit__之后
        """
        print(traceback.format_exc())
    else:
        # 没异常执行部分
        print(zero_parameter) 
    finally:
        # 结束
        print('===== 结束 ====')

with zero_func(0) as x:
    """
    这里print(x)会发现打印出一个None,这个其实是yield返回的空对象
    这里还能看出来,print(x) 虽然在后面但是执行的时候是先执行
    """
    print(x)

 

实战用两种上下文管理器实现打开文件:

第一种:

import traceback

class OpenFiles():
    def __init__(self, filename, openway):
        print('==== __init__ ====')
        self.filename = filename
        self.openway = openway
        self.file_obj = None

    def __enter__(self):
        print('==== __enter__ ====')
        self.file_obj = open(self.filename, self.openway)
        return self.file_obj

    def __exit__(self, exc_type, exc_val, exc_tb):
        print(exc_type, exc_val, traceback.print_tb(exc_tb))
        if self.file_obj:
            self.file_obj.close()
        print('==== __exit__ ====')
        return True

with OpenFiles('text.txt', 'r') as res:
    """
    如果test.txt不存在会报错,你可以用w创建一个,然后打开往里面写点东西,在改为r
    python 中如果文件不存在,r r+会报错,w w+ a a+ 会创建
    """
    print(res.readlines())

 

第二种:

import traceback
import contextlib

@contextlib.contextmanager
def open_file(filename, openway):
    print('====== __enter__ =========')
    try:
        file_obj = open(filename, openway)
        yield file_obj
        print('====== __exit__ =========')
    except Exception as exc:
        print(traceback.format_exc())
    else:
        pass
    finally:
        file_obj.close()

with open_file('text.txt', 'r') as res:
    print(res.readlines())

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章