with上下文管理协议

背景知识:

1 打印sys.exc_info()

如果没有异常返回

import sys

1/1

print(sys.exc_info())

------------------------

(None, None, None)

有异常返回

import sys

try:

    a=1/0

except:

    error=sys.exc_info()

    print(error)

    print(error[0])

    print(error[1])

    print(error[2])

------------------------------

(<class 'ZeroDivisionError'>, ZeroDivisionError('division by zero',), <traceback object at 0x0000000

00232B088>)

<class 'ZeroDivisionError'>

division by zero

<traceback object at 0x000000000232B088>

 

2 with后面的对象必须要有__enter__(),__exit__()方法否则会报错: AttributeError

>>> def P():

...     pass

...

>>> a=P()

>>> dir(a)

['__bool__', '__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__

getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__ne__'

, '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__s

ubclasshook__']

>>> with a as foo:

...     print("error")

...

Traceback (most recent call last):

  File "<stdin>", line 1, in <module>

AttributeError: __enter__

好切入正题。 

使用with处理的对象必须有__enter__(),__exit__()这两个方法(with后面的对象、with后面所返回的对象)。__enter__()方法在with语句包裹起来的代码块执行之前进入,__exit__()方法在语句执行完退出后运行。

紧跟with后面的语句被求值后,返回对象的__enter__()方法被调用,这个方法的返回值将被赋值给as后面的变量。

with语句适用于对资源访问的场合,不管执行过程中有没有异常,都会执行必要的清理工作,释放资源。比如文件使用后的自动关闭,线程中锁的自动获取和释放。

class Sample:

    def __enter__(self):

        print ("In __enter__()")

        return "Foo"

 

    def __exit__(self, type, value, trace):

        print ("In __exit__()")

 

def get_sample():

    return Sample()

 

with get_sample() as sample:

print ("sample:", sample)

 

在with后面的代码块抛出任何异常时,则使用 sys.exc_info的异常信息为参数调用 __exit__(exc_type, exc_value, exc_traceback)将type,value和trace传给__exit__()方法,开发库时,清理资源,关闭文件等等操作,都可以放在__exit__方法当中。

 

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):

        a= 1/0

        return a + 1

 

with Sample() as sample:

    sample.do_something()

-----------------------------------------

type: <class 'ZeroDivisionError'>

value: division by zero

trace: <traceback object at 0x000000000234C508>

Traceback (most recent call last):

  File "C:\Users\Administrator\Desktop\c.py", line 15, in <module>

    sample.do_something()

  File "C:\Users\Administrator\Desktop\c.py", line 11, in do_something

    bar = 1/0

ZeroDivisionError: division by zero

posted @ 2019-12-24 16:04  とうさん  阅读(187)  评论(0编辑  收藏  举报