.. _best-practices: ****************************************************************************************** 型指定のベストプラクティス ****************************************************************************************** はじめに ========================================================================================== 時間が経つにつれて、Python で型ヒントを使用する際に役立つベスト プラクティスが証明されています。 すべてのプラクティスがすべての状況に適用されるわけではなく、一部のプラクティスは個人的なスタイルや好みによるものですが、特定の理由がない限り、立ち戻るためのデフォルトの推奨事項として適しています。 逸脱する。 これらのベスト プラクティスは、特に型指定機能とエコシステムが成長するにつれて、絶えず進化しています。 したがって、型指定に関する経験についてお聞かせいただければ幸いです。 ディスカッションに参加する方法については、:ref:`contact` を参照してください。 型指定機能 ========================================================================================== 型エイリアス ------------------------------------------------------------------------------------------ 型エイリアスには ``TypeAlias`` を使用します (通常のエイリアスには使用しません)。 はい:: _IntList: TypeAlias = list[int] g = os.stat Path = pathlib.Path ERROR = errno.EEXIST いいえ:: _IntList = list[int] g: TypeAlias = os.stat Path: TypeAlias = pathlib.Path ERROR: TypeAlias = errno.EEXIST エルゴノミック プラクティス ========================================================================================== ``Any`` と ``object`` の使用 ------------------------------------------------------------------------------------------ 一般に、現在の型システムでは型を適切に表現できない場合、または正しい型を使用することが非人間的である場合は、``Any`` を使用します。 たとえば、関数が引数として可能な限りすべてのオブジェクトを受け入れる場合 (たとえば、``str()`` にのみ渡されるため)、型注釈として ``Any`` の代わりに ``object`` を使用します。 同様に、コールバックの戻り値が無視される場合は、次のように注釈を付けます ``object``:: def call_cb_if_int(cb: Callable[[int], object], o: object) -> None: if isinstance(o, int): cb(o) .. _argument-return-practices: 引数と戻り値の型 ------------------------------------------------------------------------------------------ 引数については、プロトコルと抽象型 (``Mapping``, ``Sequence``, ``Iterable`` など) を優先します。 引数が文字通り任意の値を受け入れる場合は、``Any`` の代わりに ``object`` を使用します。 戻り値については、具体的な実装には具体的な型 (``list``, ``dict`` など) を優先します。 プロトコルと抽象基本クラスの戻り値は、ケースバイケースで判断する必要があります。 はい:: def map_it(input: Iterable[str]) -> list[int]: ... def create_map() -> dict[str, int]: ... def to_string(o: object) -> str: ... # 任意のオブジェクトを受け入れます いいえ:: def map_it(input: list[str]) -> list[int]: ... def create_map() -> MutableMapping[str, int]: ... def to_string(o: Any) -> str: ... 場合によっては:: class MyProto(Protocol): def foo(self) -> list[int]: ... def bar(self) -> Mapping[str, str]: ... ``isinstance()`` チェックが必要になるため、共用体の戻り値の型は避けてください。 必要に応じて ``Any`` または ``X | Any`` を使用します。 スタイリスティック プラクティス ========================================================================================== 省略形の構文 ------------------------------------------------------------------------------------------ 可能な場合は、共用体の省略形の構文を使用し、``Union`` または ``Optional`` は使用しないでください。 ``None`` は共用体の最後の要素である必要があります。 はい:: def foo(x: str | int) -> None: ... def bar(x: str | None) -> int | None: ... いいえ:: def foo(x: Union[str, int]) -> None: ... def bar(x: Optional[str]) -> Optional[int]: ... def baz(x: None | str) -> None: ... 型 ------------------------------------------------------------------------------------------ ``int | float`` の代わりに ``float`` を使用します。 ``Literal[None]`` の代わりに ``None`` を使用します。 組み込みジェネリクス ------------------------------------------------------------------------------------------ 可能な場合は、``typing`` のエイリアスの代わりに組み込みジェネリクスを使用します。 はい:: from collections.abc import Iterable def foo(x: type[MyClass]) -> list[str]: ... def bar(x: Iterable[str]) -> None: ... いいえ:: from typing import Iterable, List, Type def foo(x: Type[MyClass]) -> List[str]: ... def bar(x: Iterable[str]) -> None: ...