且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

python中with as 语句的作用以及意义

更新时间:2022-05-14 08:09:30

简单总结

with as 语句的作用主要如下:
1、解决异常退出时资源释放的问题;
2、解决用户忘记调用close方法而产生的资源泄漏问题;
也就是说,with as方法最适合容易偷懒或者马虎的程序员了,从C/C++过来的程序员没少体验过资源泄漏以及内存问题,而withas语句就可以方便地帮助你从苦海中解脱。

详细解释:

看一下官方文档对with语句的描述:

The with statement:

The with statement is used to wrap the execution of a block with methods defined by a context manager (see section With Statement Context Managers). This allows common try…except…finally usage patterns to be encapsulated for convenient reuse.

with语句是通过一个上下文管理器定义的方法来对一段程序进行打包执行.这将让常见的try…except…finally模式用法被包装起来以便重复使用

with_stmt ::=  “with” with_item (“,” with_item)* “:” suite
with_item ::=  expression [“as” target]
#说白了就是:
with item as target:

The execution of the with statement with one “item” proceeds as follows:
使用with语句来执行一个item过程如下:

1、The context expression (the expression given in the with_item) is evaluated to obtain a context manager.
检测到上下文表达式,从而获取上下文管理器

2、The context manager’s exit() is loaded for later use.
上下文管理器的exit()方法会被载入以便之后使用

3、The context manager’s enter() method is invoked.
上下文管理器的 enter() 方法被激活(执行)

4、If a target was included in the with statement, the return value from enter() is assigned to it.
如果在with语句中目标被包含,那么来自enter()的返回值就会背附带过来。

Note The with statement guarantees that if the enter() method returns without an error, then exit() will always be called. Thus, if an error occurs during the assignment to the target list, it will be treated the same as an error occurring within the suite would be. See step 6 below.
注意,with语句遵循:如果enter ()方法返回没有错误,则exit ()将始终被调用。 因此,如果在分配给目标列表期间发生错误,则将被视为与套件内发生的错误相同。 请参阅下面的步骤6。

5、The suite is executed.
这段程序被执行

6、The context manager’s exit() method is invoked. If an exception caused the suite to be exited, its type, value, and traceback are passed as arguments to exit(). Otherwise, three None arguments are supplied.
上下文管理器的exit() 方法被执行,如果这组程序被一个意外造成终止,那么这个组程序的类型、返回值、还有跟踪反馈被当做文件传递到exit()中。如果三个参数没有被提供,这个过程将造成不一样的结果。

If the suite was exited due to an exception, and the return value from the exit() method was false, the exception is reraised. If the return value was true, the exception is suppressed, and execution continues with the statement following the with statement.
如果这段程序因为意外***终止,由exit() 方法得到的返回值为假,那么意外将会被重新提出。如果返回值是真,意外将被隐匿,程序将继续往下执行。

If the suite was exited for any reason other than an exception, the return value from exit() is ignored, and execution proceeds at the normal location for the kind of exit that was taken.
如果这段程序不是因为意外所终止,来自 exit()的返回值将被忽略,程序会在正常位置处理执行所采用的退出类型。

而上面所说的内容管理器主要是用来管理在with申明中定义的运行时内容(runtime context),也可以说是一种环境,一个状态。 该管理器实现了两个方法,一个是enter()方法,一个是exit()方法。

enter()方法主要是进入运行时内容(runtime context)并返回与之相对应的对象。 该方法的返回值的会绑定到使用该context Manager的with 语句中as标识符之后的内容。举个例子:

with open('text.txt') as file
    file.read()

该内容管理器(context manager)中的enter()方法返回的是一个文件对象,该对象赋值给了file。

exit(exc_type, exc_val, exc_tb)方法就是在结束这个运行时内容或环境(runtime context)并返回一个布尔值的变量来确定是否忽略中途出现的异常情况。如果中途在with语句中的执行体中出现了什么问题。就会把对应的异常类型,值以及回溯信息传给该方法,没有异常就传入None。如果有异常传入并且布尔值为真就忽略该异常,如果有异常传入但布尔值为假就像正常一样抛出异常。内容管理器的有点就是将try…except…finally的复用性提高。

执行一段程序测试一下输出结果

编译环境:Python3.6.2,Pycharm

class Test:
    def __enter__(self):
        print("this is in __enter__")
        return "enter_test"

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


def test_funcion():
    return Test()


if __name__ == "__main__":
    with test_funcion() as test:
        print("The Test return value is", test)

执行结果

this is in __enter__
The Test return value is enter_test
this is in __exit__