Python 上下文管理

1、语法定义

上下文管理属于流程控制特性中一部分,在python中,上下文管理语法主要是使用with关键词。with语句会设置一个临时的上下文,对对象进行控制,并且清除上下文

with context_expression [as target(s)]:
    ...
    with-body
    ...

其中 context_expression 可以是任意表达式;as target(s) 是可选的

2、由来

with…as 是 python 的控制流语句,像 if ,while一样。with…as 语句是简化版的 try except finally语句。

先理解一下 try…except…finally 语句是干啥的。实际上 try…except 语句和 try…finally 语句是两种语句,用于不同的场景。但是当二者结合在一起时,可以“实现稳定性和灵活性更好的设计”。

完整的try…finallly 语句实现:

try:  
    execution block  ##正常执行模块  
except A:  
    exc A block ##发生A错误时执行  
except B:  
    exc B block ##发生B错误时执行  
except:  
    other block ##发生除了A,B错误以外的其他错误时执行  
else:  
    if no exception, jump to here ##没有错误时执行  
finally:  
	final block  ##总是执行

tips: 注意顺序不能乱,否则会有语法错误。如果用 else 就必须有 except,否则会有语法错误。

try:
    a = 1 / 2
    print(a)
    print(m)  # 抛出 NameError异常, 此后的语句都不在执行
    b = 1 / 0
    print(b)
    c = 2 / 1
    print(c)
except NameError:
    print("Ops!!")  # 捕获到异常
except ZeroDivisionError:
    print("Wrong math!!")
except:
    print("Error")
else:
    print("No error! yeah!")
finally:  # 是否异常都执行该代码块

3、with 语句的原理

  • 上下文管理协议(Context Management Protocol):包含方法 enter() 和
    exit(),支持该协议的对象要实现这两个方法。
  • 上下文管理器(Context Manager):支持上下文管理协议的对象,这种对象实现了 enter() 和 exit()
    方法。上下文管理器定义执行 with 语句时要建立的运行时上下文,负责执行 with 语句块上下文中的进入与退出操作。通常使用 with
    语句调用上下文管理器,也可以通过直接调用其方法来使用。

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)

程序有错的例子:

class Sample:
    def __enter__(self):
        return self
 
    def __exit__(self, type, value, trace):
        print("type:", type)
        print("value:", value)
        print("trace:", trace)
 
    def do_something(self):
        bar = 1 / 0
        return bar + 10
 
 
with Sample() as sample:
    sample.do_something()

Python 上下文管理_第1张图片
步骤分析:
–> 实例化Sample类,执行类方法__enter__(),返回值self也就是实例自己赋值给sample。即sample是Sample的一个实例(对象);
–>执行with-block码块: 实例sample调用方法do_something();
–>执行do_something()第一行 bar = 1 / 0,发现ZeroDivisionError,直接结束with-block代码块运行
–>执行类方法__exit__(),带入ZeroDivisionError的错误信息值,也就是type,value, trace,并打印它们。

你可能感兴趣的:(python,python,开发语言)