Tengo una situación en la que quiero salir de un bucle for asíncrono. Logré reducir el problema a la aplicación a continuación. Espero ingresar a la sección 'finalmente' del administrador de contexto al salir del bucle en main. En otras palabras, el resultado esperado es
tratar
456
por fin
hecho
pero lo que obtengo es
tratar
456
hecho
por fin
y luego una excepción cuando se cierra la aplicación.
Aquí está el código
import asyncio from contextlib import asynccontextmanager @asynccontextmanager async def receiving(): try: print('try') yield 123 finally: print('finally') async def request_all(): async with receiving(): yield 456 async def main(): async for r in request_all(): print(r) break print('done') asyncio.run(main())Encontré este informe de error que parece similar, pero que yo sepa, se resolvió antes de la versión 3.8. Probé mi problema en 3.8.2 y 3.9.6
Puedo ver cómo este comportamiento es confuso, pero no creo que sea un error. Si omite el agotamiento del iterador asíncrono con break , nunca deja el async with en request_all , por lo que el bloque finally no se ejecutará hasta que finalice el bucle de eventos. Esto tiene la ventaja de que podría agotar el generador en un momento posterior.
Si está seguro de que ya no necesita su generador, puede cerrar async_generator en lugar de break para obtener el comportamiento esperado:
import asyncio from contextlib import asynccontextmanager @asynccontextmanager async def receiving(): try: print('try') yield 123 finally: print('finally') async def request_all(): async with receiving(): yield 456 async def main(): gen = request_all() async for r in gen: print(r) await gen.aclose() #instead of break print('done') asyncio.run(main())