PEP 781: Adding __type_checking__ constant を書いた

まだPR段階なので peps.python.org では表示されていません。Discussionはこちらです。

PEP 781: Adding __type_checking__ constant - PEPs - Discussions on Python.org

今までもtypingのインポートを避けるために from typing import TYPE_CHECKING の代わりに TYPE_CHECKING = Falseif False: # TYPE_CHECKING のようなコードが書かれてきました。 typing.TYPE_CHECKING と同じ役割を持つ定数として __type_checking__ を追加することで、これらのワークアラウンドを不要にします。

また、 __type_checking__ は False と同じく本物の定数です。コンパイル時にコードを削除できます。

たとえば次のコードでは、実際に関数オブジェクトを4つ生成し、3つを overload のレジストリに追加しています。

# https://github.com/sqlalchemy/sqlalchemy/blob/dabd77992d785cad89ed110acd2f648a454fb7ae/lib/sqlalchemy/sql/elements.py#L133-L191

@overload
def literal(
    value: Any,
    type_: _TypeEngineArgument[_T],
    literal_execute: bool = False,
) -> BindParameter[_T]: ...


@overload
def literal(
    value: _T,
    type_: None = None,
    literal_execute: bool = False,
) -> BindParameter[_T]: ...


@overload
def literal(
    value: Any,
    type_: Optional[_TypeEngineArgument[Any]] = None,
    literal_execute: bool = False,
) -> BindParameter[Any]: ...


def literal(
    value: Any,
    type_: Optional[_TypeEngineArgument[Any]] = None,
    literal_execute: bool = False,
) -> BindParameter[Any]:
    r"""Return a literal clause, bound to a bind parameter.
    ...
    """
    return coercions.expect(
        roles.LiteralValueRole,
        value,
        type_=type_,
        literal_execute=literal_execute,
    )

overloadの定義部分を if TYPE_CHECKING: で囲えばオーバーロードのための関数オブジェクトの生成とレジストリへの追加を避けられますが、 if __type_checking__: で囲うことでその関数オブジェクトを生成するために必要なバイトコードも削って pyc ファイルを小さくできるので、WASMなどの環境でなるべくコードを小さくしたい場合でも積極的にtype hintをかけるようになります。

このブログに乗せているコードは引用を除き CC0 1.0 で提供します。