You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

关于Python异步上下文管理器方法__aenter__与__aexit__返回类型的定义疑问

Async Context Manager Return Types for __aenter__ and __aexit__

Great question—let's clear up the confusion around async context manager method return types, specifically for your MyService implementation.

First, let's address the core misunderstanding: the docs don't say __aenter__ and __aexit__ must return an awaitable directly. Instead, when implementing an async context manager, you have two valid options:

  1. Define the methods as async def (which makes them return a coroutine, a built-in type of awaitable automatically)
  2. Define them as regular def methods that explicitly return an awaitable object

Your current implementation uses the first (and more common) approach, which is perfectly valid. Now let's break down each method's return type in detail:

__aenter__ Return Type

For __aenter__, the goal is to return the object you want bound to the variable in async with MyService(...) as service:. In your case, that's the MyService instance itself.

Since you've defined __aenter__ as an async def method, Python automatically treats it as an awaitable. The return type annotation should reflect the value you get after awaiting the method—which is your MyService instance.

Your existing annotation -> "MyService" is correct. The string quote is needed because the MyService class isn't fully defined when the method is annotated (you can also use from __future__ import annotations in Python 3.7+ to avoid the quotes entirely).

__aexit__ Return Type

The __aexit__ method controls whether exceptions raised inside the async with block are suppressed or propagated:

  • If it returns a truthy value (like True), the exception is suppressed.
  • If it returns a falsy value (like None or False), the exception propagates normally.

For async __aexit__ methods:

  • The method itself is an awaitable, so Python will await it automatically.
  • The return type annotation should reflect the value you get after awaiting—either None (if you don't intend to suppress exceptions) or bool (if you might return True to suppress exceptions in specific cases).

In your current code, you're returning None implicitly (since there's no explicit return statement), which is perfectly fine. Annotating it as -> None is correct. If you ever need to suppress exceptions (e.g., handle a specific error and return True), you can update the annotation to -> bool.

Updated Code with Correct Annotations

Here's your code with proper type hints (plus a stub MyAPI for completeness):

from typing import Any
from __future__ import annotations  # Optional, allows using MyService instead of "MyService"

class MyAPI:
    async def init(self) -> None:
        pass
    
    async def close(self) -> None:
        pass

class MyService:
    def __init__(self, my_api: MyAPI) -> None:
        self._my_api = my_api
        self._session_usage_count = 0

    async def __aenter__(self) -> MyService:
        if not self._session_usage_count:
            await self._my_api.init()
        self._session_usage_count += 1
        return self

    async def __aexit__(self, *exc: Any) -> None:
        self._session_usage_count -= 1
        if not self._session_usage_count:
            await self._my_api.close()

Key Takeaways

  • __aenter__ (async method): Annotate with the type of object you want to expose to the async with block (usually self's type).
  • __aexit__ (async method): Annotate with None if you don't suppress exceptions, or bool if you might return True to suppress them.

内容的提问来源于stack exchange,提问作者Ivan Petrushenko

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.30 03:42:38