python - 上下文管理器

一、什么是上下文管理器

你是不是这样读过文件

with open("file","r") as f_reader:
    content  = f_reader.readlines()

为什么你要用"with"呢,因为在这段读取文件代码结束后,会自动执行close()

with是一个神奇的关键字,它可以在代码中开辟一段由它管理的上下文,并控制程序在进入和退出这段上下文时的行为,即进入时打开文件,并返回文件对像,退出时关闭文件对像

二、自定义上下文管理器

1、自定义上下文管理器

并不是只有文件才能用上下文管理器,只要满足上下文管理器协议都可以

上下文管理器定义了“进入”和“退出”动作的特殊对像,要创建一个上下文管理器,只要实现__enter__和__exit__两处魔法方法

我们再举个例子

class SayHelloTo:
    def __init__(self,name):
        self.name = name


    def __enter__(self):
        # __enter__在进入管理器时被调用,返回结果通过as关键字获取,传给as后面的变量
        return f"say hello to {self.name}"


    def __exit__(self, exc_type, exc_val, exc_tb):
        #__exit__ 会在执行结束后调用
        print("exit")
        return False



with SayHelloTo("monkey") as s:
    print(s)



输出:
say hello to monkey
exit

2、知道了这个,我们看看另一种上下文管理器的方式

使用@contextmanager装饰器,在contextmanager模块下

from contextlib import contextmanager

@contextmanager
def say_hello_to(person_name):
    result = f"say hello to {person_name}"
    #yield之前表示—__enter__内容,yield后面表示__exit__内容,yield后面的变量你可以 
    #理解成__enter__的返回值
    yield result  
    print("exit")


with say_hello_to("leilei") as s:
    print(s)

3、看了以上,猜猜你会懵逼在什么地方

 def __exit__(self, exc_type, exc_val, exc_tb):
        #__exit__ 会在执行结束后调用
        print("exit")
        return False

exit后面的参数是什么,return Flase是干啥,那可不可以return True呢

这就要说上下文管理器另一种常用方式,忽略某些不必要的异常

其实我也没想出来哪些异常不必要,那我们就举个不恰当的例子,比如说

json.loads('{"123":{134}}')

明眼人一看出来。就会报:json.decoder.JSONDecodeError 异常

那我怎样忽略异常呢:

import json


class IgnoreJsonException:
    def __enter__(self):
        pass
    def __exit__(self, exc_type, exc_val, exc_tb):
        if exc_type == json.decoder.JSONDecodeError :
            return True
        return False



with IgnoreJsonException():
    json.loads('{"123":{134}}') #运行结果没有报任何异常

1、exc_type:异常类型

2、 exc_val:异常对像,如果在上面的例子,他的值是“Expecting property name enclosed in double quotes: line 1 column 9 (char 8)”

3、exc_tb:错误的堆栈对像

当然如果没有异常的情况下,上面三个参数值都是None

返回True:这个异常会被当前的with语音压制住,不会报出

返回Flase:那这个异常就会正常抛出,交由调用方处理

我换个输入

class IgnoreJsonException:
    def __enter__(self):
        pass
    def __exit__(self, exc_type, exc_val, exc_tb):
        if exc_type == json.decoder.JSONDecodeError :
            return True
        return False

with IgnoreJsonException():
    #我现在传入的是none,则他抛出的不是json.decoder.JSONDecodeError异常,所以 
    #走了return False的分支,异常会原封不动的被抛出
    json.loads(None) 



运行结果:
Traceback (most recent call last):
  File "D:/practice_code/Practice/exception_demo/demo05.py", line 20, in 
    json.loads(None)
  File "D:\work_tools\python\lib\json\__init__.py", line 341, in loads
    raise TypeError(f'the JSON object must be str, bytes or bytearray, '
TypeError: the JSON object must be str, bytes or bytearray, not NoneType

 三、另一种忽略异常的方式 contextlib库中的suppress函数,是不是更简单

import json
from contextlib import suppress

with suppress(json.decoder.JSONDecodeError):
    json.loads('{"123":{134}}')

你可能感兴趣的:(python杂记,python)