廃止された型機能のモダナイズ

はじめに

このガイドでは、古い型機能を最新のものに置き換えることでコードをモダナイズする方法を説明します。 ここで説明するすべての機能が廃止されているわけではありませんが、より最新の代替機能によって置き換えられており、これらの代替機能の使用が推奨されます。

これらの新しい機能はすべての Python バージョンで利用できるわけではありませんが、一部の機能は typing-extensions パッケージからのバックポートとして利用できるか、引用または from __future__ import annotations を使用する必要があります。 各セクションでは、機能を使用するために必要な最小 Python バージョン、typing-extensions で利用可能かどうか、および引用を使用して利用可能かどうかを示しています。

注釈

typing-extensions の最新バージョンは、サポートが終了していないすべての Python バージョンで利用できますが、古いバージョンでは必ずしも利用できるとは限りません。

注釈

from __future__ import annotations は Python 3.7 以降で利用可能です。 これは型注釈内でのみ効果があり、引用は依然として外部で必要です。 たとえば、この例は Python 3.7 以降で実行されますが、パイプ演算子は Python 3.10 で導入されました:

from __future__ import annotations
from typing_extensions import TypeAlias

def f(x: int | None) -> int | str: ...  # future import で十分です
Alias: TypeAlias = "int | str"  # これは引用が必要です

型コメント

代替機能が利用可能になったのは: Python 3.0, 3.6

型コメントは元々、Python 2 および Python 3.6 より前のバージョンで変数注釈をサポートするために導入されました。 ほとんどの型チェッカーは依然としてサポートしていますが、これらは廃止されたと見なされており、型チェッカーはそれらをサポートする必要はありません。

たとえば、次のように置き換えます:

x = 3  # type: int
def f(x, y):  # type: (int, int) -> int
    return x + y

次のように置き換えます:

x: int = 3
def f(x: int, y: int) -> int:
    return x + y

前方参照や型チェック時にのみ利用可能な型を使用する場合は、from __future__ import annotations (Python 3.7 以降で利用可能) を使用するか、型を引用する必要があります:

def f(x: "Parrot") -> int: ...

class Parrot: ...

typing.Text

代替機能が利用可能になったのは: Python 3.0

typing.Text は Python 2 互換性のための型エイリアスでした。 これは str と同等であり、置き換える必要があります。 たとえば、次のように置き換えます:

from typing import Text

def f(x: Text) -> Text: ...

次のように置き換えます:

def f(x: str) -> str: ...

typing.TypedDict レガシーフォーム

代替機能が利用可能になったのは: Python 3.6

TypedDict は、変数注釈をサポートしない Python バージョンをサポートするための 2 つのレガシーフォームをサポートしています。 次の 2 つのバリアントを置き換えます:

from typing import TypedDict

FlyingSaucer = TypedDict("FlyingSaucer", {"x": int, "y": str})
FlyingSaucer = TypedDict("FlyingSaucer", x=int, y=str)

次のように置き換えます:

class FlyingSaucer(TypedDict):
    x: int
    y: str

ただし、キーが有効な Python 識別子でない場合は、辞書形式が依然として必要です:

Airspeeds = TypedDict("Airspeeds", {"unladen-swallow": int})

typing モジュールのジェネリクス

代替機能が利用可能になったのは: Python 3.0 (引用), Python 3.9 (非引用)

元々、typing モジュールは、型パラメーターを受け入れる組み込み型のエイリアスを提供していました。 Python 3.9 以降、これらのエイリアスは不要になり、組み込み型に置き換えることができます。 たとえば、次のように置き換えます:

from typing import Dict, List

def f(x: List[int]) -> Dict[str, int]: ...

次のように置き換えます:

def f(x: list[int]) -> dict[str, int]: ...

これには次の型が影響します:

typing モジュールは、型パラメーターを受け入れる特定の標準ライブラリ型のエイリアスも提供していました。 Python 3.9 以降、これらのエイリアスは不要になり、適切な型に置き換えることができます。 たとえば、次のように置き換えます:

from typing import DefaultDict, Pattern

def f(x: Pattern[str]) -> DefaultDict[str, int]: ...

次のように置き換えます:

from collections import defaultdict
from re import Pattern

def f(x: Pattern[str]) -> defaultdict[str, int]: ...

これには次の型が影響します:

typing.Union および typing.Optional

代替機能が利用可能になったのは: Python 3.0 (引用), Python 3.10 (非引用)

Union および Optional は廃止されたとは見なされていませんが、| (パイプ) 演算子を使用する方が読みやすい場合がよくあります。 Union[X, Y]X | Y と同等であり、Optional[X]X | None と同等です。

たとえば、次のように置き換えます:

from typing import Optional, Union

def f(x: Optional[int]) -> Union[int, str]: ...

次のように置き換えます:

def f(x: int | None) -> int | str: ...

typing.NoReturn

代替機能が利用可能になったのは: Python 3.11, typing-extensions

Python 3.11 では、typing.NoReturn のエイリアスとして typing.Never が導入され、戻り値の型ではない注釈で使用されます。 たとえば、次のように置き換えます:

from typing import NoReturn

def f(x: int, y: NoReturn) -> None: ...

次のように置き換えます:

from typing import Never  # または typing_extensions.Never

def f(x: int, y: Never) -> None: ...

ただし、戻り値の型には NoReturn を使用します:

from typing import NoReturn

def f(x: int) -> NoReturn: ...

型エイリアス

代替機能が利用可能になったのは: Python 3.12 (キーワード); Python 3.10, typing-extensions

元々、型エイリアスは単純な代入を使用して定義されていました:

IntList = list[int]

Python 3.12 では、型エイリアスを定義するための type キーワードが導入されました:

type IntList = list[int]

古い Python バージョンをサポートするコードは、Python 3.10 で導入されたが typing-extensions でも利用可能な TypeAlias を代わりに使用する必要があります:

from typing import TypeAlias  # または typing_extensions.TypeAlias

IntList: TypeAlias = list[int]

ユーザー定義ジェネリクス

代替機能が利用可能になったのは: Python 3.12

Python 3.12 では、ジェネリック クラスを定義するための新しい構文が導入されました。 以前は、ジェネリック クラスは typing.Generic (または他のジェネリック クラス) から派生し、型変数は typing.TypeVar を使用して定義されていました。 たとえば:

from typing import Generic, TypeVar

T = TypeVar("T")

class Brian(Generic[T]): ...
class Reg(int, Generic[T]): ...

Python 3.12 以降、型変数は TypeVar を使用して宣言する必要がなくなり、クラスを Generic から派生させる代わりに次の構文を使用できます:

class Brian[T]: ...
class Reg[T](int): ...

typing.ByteString

代替機能が利用可能になったのは: Python 3.0; Python 3.12, typing-extensions

ByteString は元々、bytesbytearray、および memoryview のような「バイト型」の型のエイリアスとして意図されていました。 実際には、これはほとんどの場合、正確に必要なものではありません。 代わりに次のいずれかの代替案を使用します:

  • 公開 API を宣言しない場合は、単に bytes で十分な場合がよくあります。

  • buffer protocol をサポートする任意の型を受け入れる項目には、collections.abc.Buffer (Python 3.12 以降で利用可能) または typing_extensions.Buffer を使用します。

  • それ以外の場合は、bytesbytearraymemoryview、および/または受け入れられる他の型の共用体を使用します。

typing.Hashable および typing.Sized

代替機能が利用可能になったのは: Python 3.12, typing-extensions

次の typing の抽象基本クラスは、Python 3.12 で collections.abc に追加されました:

インポートを新しい場所に更新します:

from collections.abc import Hashable, Sized

def f(x: Hashable) -> Sized: ...