python中关于with语句的用法

上下文管理器类型

Python 标准库非常庞大,所提供的组件涉及范围十分广泛。这个库包含了多个内置模块 (以 C 编写),Python 程序员必须依靠它们来实现系统级功能,例如文件 I/O,此外还有大量以 Python 编写的模块,提供了日常编程中许多问题的标准解决方案。其中有些模块经过专门设计,通过将特定平台功能抽象化为平台中立的 API 来鼓励和加强 Python 程序的可移植性。

而上下文管理器类型就是作为Python标准库中的内置类型的一种而存在的。

with的完整语句为:

with expression1 [as var]:
    expression2

Python 的 with语句支持通过上下文管理器所定义的运行时上下文这一概念。 此对象的实现使用了一对专门方法,允许用户自定义类来定义运行时上下文,在语句体被执行前进入该上下文,并在语句执行完毕时退出该上下文:

contextmanager.__enter__()

进入运行并返回此对象或关联到该运行时上下文的其他对象。 此方法的返回值会绑定到使用此上下文管理器的 with语句的 as 子句中的标识符。

contextmanager.__exit__(exc_type, exc_val, exc_tb)

退出运行上下文并返回一个布尔值来表明所发生的任何异常是否应当被屏蔽。 如果在执行with语句的语句体期间发生了异常,则参数会包含异常的类型、值以及回溯信息。 在其他情况下三个参数均为 None。

此方法返回一个真值将导致 with语句屏蔽异常并继续执行紧随在 with语句之后的语句。 否则异常将在此方法结束执行后继续传播。 在此方法执行期间发生的异常将会取代 with语句的语句体中发生的任何异常。

传入的异常绝对不应当被显式地重新引发 —— 相反地,此方法应当返回一个假值以表明方法已成功完成并且不希望屏蔽被引发的异常。 这允许上下文管理代码方便地检测 __exit__() 方法是否确实已失败。

with 语句上下文管理器

上下文管理器是一个对象,它定义了在执行 with 语句时要建立的运行时上下文。 上下文管理器处理进入和退出所需运行时上下文以执行代码块。 通常使用 with语句,但是也可以通过直接调用它们的方法来使用。

上下文管理器的典型用法包括保存和恢复各种全局状态,锁定和解锁资源,关闭打开的文件等等。

object.__enter__(self)

进入与此对象相关的运行时上下文。 with语句将会绑定这个方法的返回值到 as 子句中指定的目标,如果有的话。

object.__exit__(self, exc_type, exc_value, traceback)

退出关联到此对象的运行时上下文。 各个参数描述了导致上下文退出的异常。 如果上下文是无异常地退出的,三个参数都将为 None。

如果提供了异常,并且希望方法屏蔽此异常(即避免其被传播),则应当返回真值。 否则的话,异常将在退出此方法时按正常流程处理。__exit__() 方法不应该重新引发被传入的异常。

with语句

with 语句用于包装带有使用上下文管理器定义的方法的代码块的执行。 这允许对普通的 try...except...finally 使用模式进行封装以方便地重用。

with_stmt ::=  "with" with_item ("," with_item)* ":" suite
with_item ::=  expression ["as" target]

带有一个“项目”的 with 语句的执行过程如下:

  1. 对上下文表达式 (在 with_item 中给出的表达式) 求值以获得一个上下文管理器。

  2. 载入上下文管理器的 __exit__() 以便后续使用。

  3. 发起调用上下文管理器的 __enter__() 方法。

  4. 如果 with 语句中包含一个目标,来自 __enter__() 的返回值将被赋值给它。

    注解:with 语句会保证如果 __enter__() 方法返回时未发生错误,则 __exit__() 将总是被调用。 因此,如果在对目标列表赋值期间发生错误,则会将其视为在语句体内部发生的错误。 参见下面的第 6 步。

  5. 执行语句体。

  6. 发起调用上下文管理器的 __exit__() 方法。 如果语句体的退出是由异常导致的,则其类型、值和回溯信息将被作为参数传递给 __exit__()。 否则的话,将提供三个 None参数。

    如果语句体的退出是由异常导致的,并且来自 __exit__() 方法的返回值为假,则该异常会被重新引发。 如果返回值为真,则该异常会被抑制,并会继续执行 with 语句之后的语句。

    如果语句体由于异常以外的任何原因退出,则来自 __exit__() 的返回值会被忽略,并会在该类退出正常的发生位置继续执行。

 如果有多个项目,则会视作存在多个 with 语句嵌套来处理多个上下文管理器:

with A() as a, B() as b:
    suite

等价于

with A() as a:
    with B() as b:
        suite

实例

class Mycontextmanager(object):
    def __init__(self,name):
        self.name=name
    def __enter__(self):
        print("enter")
        return self
    def do_self(self):
        print(self.name)
    def __exit__(self,exc_type,exc_value,traceback):
        print("exit")
        print(exc_type,exc_value,traceback)
        
if __name__ == '__main__':
    with Mycontextmanager('test') as var:
        var.do_self()

运行结果:

enter
test
exit
None None None

当程序出现错误时:

class Mycontextmanager(object):
    def __init__(self,name):
        self.name=name
    def __enter__(self):
        print("enter")
        return self
    def do_self(self):
        print(self.name)
        print(self.state)
    def __exit__(self,exc_type,exc_value,traceback):
        print("exit")
        print(exc_type,exc_value,traceback)
        
if __name__ == '__main__':
    with Mycontextmanager('test') as var:
        var.do_self()

运行结果:

enter
test
exit
<class 'AttributeError'> 'Mycontextmanager' object has no attribute 'state' <traceback object at 0x00000243FD5BE048>
Traceback (most recent call last):
  File "C:\Users\xxx\Desktop\test.py", line 16, in <module>
    var.do_self()
  File "C:\Users\xxx\Desktop\test.py", line 9, in do_self
    print(self.state)
AttributeError: 'Mycontextmanager' object has no attribute 'state'

仍旧可以执行 __exit__() 退出 with 语句。

参考资料

1:Python官方文档:https://docs.python.org/3.7/

2:用户skullfang的简书:https://www.jianshu.com/p/5b01fb36fd4c

  • 3
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值