with as 如何工作

with如何工作?

Python对with的处理还是很机智滴.基本思想就是with所求值的对象必须有一个__enter__()方法,一个__exit__()方法

紧跟with后面的语句被求值后,返回对象的__enter__()方法被调用,这个方法的返回值将被赋值给as后面的变量,当with后面的代码块全部被执行完之后,将调用前面返回对象的__exit__()方法.

下面例子可以具体说明with如何工作

class Sample:
    def __enter__(self):
        print("in __enter__")
        return "foo"  # 返回值赋值给了"sample",所以下面代码打印的foo

    def __exit__(self, exc_type, exc_val, exc_tb):
        print("in __exit__()")


def get_sample():
    return Sample()

with get_sample() as sample:
    print("sample", sample)

运行代码,输出如下

in __enter__
sample foo
in __exit__()

1,__enter__()方法被执行

2,__enter__()方法返回的值 - 这个例子中的"foo",赋值给变量"sample"

3,执行代码块,打印变量"smple"的值为"foo"

4,__exit__()方法被调用

with真正强大之处是他可以处理异常,可能你已经注意到Sample类的__exit__方法有三个参数

exc_type,exc_val,exc_tb.这些参数在异常处理中相当有用,我们开修改下代码:

class Sample:
    def __enter__(self):
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        print("type: ", exc_type)
        print("value: ", exc_val)
        print("trace: ", exc_tb)

    def do_something(self):
        bar = 1/0
        return bar + 10

with Sample() as sample:
    sample.do_something()

这个例子中,wilt后面的get_sample()变成了Sample().这没有任何关系.只要紧跟with后面的语句所返回的对象有__enter__()和__exit__()方法即可,此例中,Sample()的__enter__()方法返回新创建的Sample对象,并赋值给变量sample.

代码执行后:

type:  <class 'ZeroDivisionError'>
value:  division by zero
trace:  <traceback object at 0x00000192D8305108>
Traceback (most recent call last):
  File "D:/数据管理/python全栈开发13期/网络编程/day_39/队列.py", line 164, in <module>
    sample.do_something()
  File "D:/数据管理/python全栈开发13期/网络编程/day_39/队列.py", line 160, in do_something
    bar = 1/0
ZeroDivisionError: division by zero

实际上,在with后面的代码块抛出任何异常时,__exit__()方法被执行.正如例子所示,异常抛出时,与之关联的type,value和trace传给__exit__()方法,因此判处的ZeroDivisionError异常被打印出来了.开发库,清理资源,关闭文件等等操作,都可以放在__exit__()方法当中.

因此,Python的with语句时提供了一个有效的机制,让代码更简练,同时在异常产生时,清理工作更简单.

猜你喜欢

转载自www.cnblogs.com/chenrun/p/9373721.html