14.__aenter__和__aexit__函数

关于__aenter__和__aexit__函数

# 示例一:概述
import asyncio

class Test():

    def __init__(self):
        print("Init!")

    def __enter__(self):
        print("Enter!")

    def __exit__(self, type, value, trace):
        print("Exit!")

    async def __aenter__(self):
        print("async Enter!")

    async def __aexit__(self, type, value, trace):
        print("async Exit!")

async def main():
    async with Test() as f:            # async with as语句
        print("f:", f)
        print("Have a try!")  

    print("Done!")            

if __name__ == "__main__":

    loop = asyncio.get_event_loop()    # 创建事件循环
    loop.run_until_complete(main())    # 异步函数不能简单直接调用,所以这里放在了一个事件循环里面

    print("Loop finished!")

# Init!
# async Enter!
# f: None
# Have a try!
# async Exit!
# Done!
# Loop finished!
在以上例子中,注意点及执行顺序如下:

执行async with as语句时,首先通过Test()创建一个示例,因此首先打印"Init!";
执行async with as语句时,__aenter__函数会被调用,与__enter__函数无关,因此打印"async Enter!",而不是"Enter!"
__aenter__函数返回的对象会成为f,这里__aenter__函数没有return语句,默认返回None,因此f就是None
打印"Have a try!"
async with as语句块执行完毕,调用__aexit__语句,打印"async Exit!"
事件循环结束,最后打印"Loop finished!"
# 示例二:__aexit__的三个参数
# 与__exit__函数一样,__aexit__函数也有三个参数,这是拿来处理async with as语句块中的异常。
# 注意:它并不能处理__aenter__和__aexit__函数内部的异常。举个例子如下:
import asyncio

class Test():

    def __init__(self):
        print("Init!")

    def __enter__(self):
        print("Enter!")

    def __exit__(self, type, value, trace):
        print("Exit!")

    async def __aenter__(self):
        print("async Enter!")

    async def __aexit__(self, type, value, trace):
        print("type:", type)
        print("value:", value)
        print("trace:", trace)
        print("async Exit!")
        return True                    # 这个return True是什么意思呢?

async def main():
    async with Test() as f:            # async with as语句
        print("f:", f)
        a = 1 / 0
        print("Have a try!")           # 猜猜这句话会不会执行?

if __name__ == "__main__":

    loop = asyncio.get_event_loop()    # 创建事件循环
    loop.run_until_complete(main())    # 异步函数不能简单直接调用,所以这里放在了一个事件循环里面

    print("Loop finished!")            # 猜猜这句话会不会执行?

# Init!
# async Enter!
# f: None
# type: <class 'ZeroDivisionError'>
# value: division by zero
# trace: <traceback object at 0x000002CB429DBC08>
# async Exit!
# Loop finished!
在以上例子中,注意点及执行顺序如下:

执行async with as语句块中a = 1 / 0时遇到异常,直接调用__aexit__函数,打印出对应异常的type,value和traceback;
注意__aexit__函数中return True的意思是直接跳出async with as语句块,但是不会影响async with as语句块后面的code,因此"Have a try!"不会打印,
而"Loop finished!"会被打印出来。