Pythonの型の紹介¶
Pythonにはオプションの「型ヒント」(「型アノテーション」とも呼ばれる)のサポートがあります。
これらの「型ヒント」またはアノテーションは、変数の型を宣言できる特殊な構文です。
変数に型を宣言することで、エディターやツールはより良いサポートを提供できます。
これはPythonの型ヒントに関する簡単なチュートリアル/復習です。FastAPIで使用するために必要な最低限のことがカバーされています...実際にはごくわずかです。
FastAPIはすべてこれらの型ヒントに基づいており、多くの利点とメリットをもたらします。
しかし、FastAPIを一度も使用しなくても、それらについて少し学ぶことで利益を得ることができます。
Note
Pythonの専門家で、型ヒントについてすべて知っている場合は、次の章に進んでください。
動機¶
簡単な例から始めましょう
def get_full_name(first_name, last_name):
full_name = first_name.title() + " " + last_name.title()
return full_name
print(get_full_name("john", "doe"))
このプログラムを呼び出すと出力されます
John Doe
関数は次のことを行います
first_nameとlast_nameを受け取ります。- それぞれの最初の文字を
title()で大文字に変換します。 - それらを間にスペースを入れて連結します。
def get_full_name(first_name, last_name):
full_name = first_name.title() + " " + last_name.title()
return full_name
print(get_full_name("john", "doe"))
編集する¶
これは非常にシンプルなプログラムです。
しかし、今、あなたがそれをゼロから書いていると想像してください。
ある時点で関数の定義を開始し、パラメーターの準備ができていました...
しかし、その後、「最初の文字を大文字に変換するメソッド」を呼び出す必要があります。
それはupperでしたか?uppercaseでしたか?first_uppercaseでしたか?capitalizeでしたか?
そして、古くからのプログラマーの友人であるエディターのオートコンプリートを試します。
関数の最初のパラメーターfirst_nameを入力し、次にドット(.)を入力し、Ctrl+Spaceを押して補完をトリガーします。
しかし、残念ながら、何も有用なものは得られません

型を追加する¶
前のバージョンから1行だけ変更しましょう。
この断片、関数のパラメーターを正確に変更します。
first_name, last_name
から
first_name: str, last_name: str
それだけです。
これらが「型ヒント」です
def get_full_name(first_name: str, last_name: str):
full_name = first_name.title() + " " + last_name.title()
return full_name
print(get_full_name("john", "doe"))
これは、次のようにデフォルト値を宣言することとは異なります
first_name="john", last_name="doe"
それは別のことです。
コロン(:)を使用しており、等号(=)ではありません。
そして、型ヒントを追加しても、通常、それらがない場合と比べて何かが変わることはありません。
しかし今、型ヒントを使って関数を作成している最中だと想像してください。
同じ時点で、Ctrl+Spaceでオートコンプリートをトリガーしようとすると、次のように表示されます

これを使えば、オプションをスクロールして、「ピンとくる」ものを見つけることができます。

さらなる動機¶
この関数を確認してください。すでに型ヒントがあります。
def get_name_with_age(name: str, age: int):
name_with_age = name + " is this old: " + age
return name_with_age
エディターが変数の型を知っているので、補完だけでなく、エラーチェックも得られます。

これで、ageをstr(age)で文字列に変換して修正する必要があることがわかります。
def get_name_with_age(name: str, age: int):
name_with_age = name + " is this old: " + str(age)
return name_with_age
型を宣言する¶
型ヒントを宣言する主な場所を見ました。関数のパラメーターとしてです。
これはFastAPIでそれらを使用する主な場所でもあります。
単純な型¶
strだけでなく、すべての標準Python型を宣言できます。
例えば、次のように使用できます
intfloatboolbytes
def get_items(item_a: str, item_b: int, item_c: float, item_d: bool, item_e: bytes):
return item_a, item_b, item_c, item_d, item_d, item_e
型パラメーターを持つジェネリック型¶
dict、list、set、tupleのように、他の値を含めることができるデータ構造がいくつかあります。そして、内部の値も独自の型を持つことができます。
内部型を持つこれらの型は「ジェネリック」型と呼ばれます。そして、それらを宣言することが可能であり、内部型も指定できます。
これらの型と内部型を宣言するには、標準Pythonモジュールtypingを使用できます。これはこれらの型ヒントをサポートするために特別に存在します。
新しいバージョンのPython¶
typingを使用する構文は、Python 3.6から最新バージョン(Python 3.9、Python 3.10など)まですべてのバージョンと互換性があります。
Pythonの進化に伴い、新しいバージョンではこれらの型アノテーションのサポートが向上しており、多くの場合、型アノテーションを宣言するためにtypingモジュールをインポートして使用する必要すらありません。
プロジェクトにPythonのより新しいバージョンを選択できる場合、その追加のシンプルさを活用できます。
すべてのドキュメントには、Pythonの各バージョンと互換性のある例が(違いがある場合に)記載されています。
例えば「Python 3.6+」はPython 3.6以降(3.7、3.8、3.9、3.10などを含む)と互換性があることを意味し、「Python 3.9+」はPython 3.9以降(3.10などを含む)と互換性があることを意味します。
最新バージョンのPythonを使用できる場合は、最新バージョンの例を使用してください。それらは最も優れたシンプルな構文を持っています。例えば、「Python 3.10+」です。
リスト¶
例えば、変数をstrのlistとして定義しましょう。
同じコロン(:)構文で変数を宣言します。
型としてlistを置きます。
リストはいくつかの内部型を含む型なので、それらを角括弧で囲みます。
def process_items(items: list[str]):
for item in items:
print(item)
typingからList(大文字のL)をインポートします。
from typing import List
def process_items(items: List[str]):
for item in items:
print(item)
同じコロン(:)構文で変数を宣言します。
型として、typingからインポートしたListを置きます。
リストはいくつかの内部型を含む型なので、それらを角括弧で囲みます。
from typing import List
def process_items(items: List[str]):
for item in items:
print(item)
情報
角括弧内のこれらの内部型は「型パラメーター」と呼ばれます。
この場合、strはList(またはPython 3.9以降ではlist)に渡される型パラメーターです。
これは、「変数itemsはlistであり、このリスト内の各項目はstrである」ことを意味します。
ヒント
Python 3.9以降を使用している場合、typingからListをインポートする必要はなく、代わりに通常のlist型を使用できます。
そうすることで、リストの項目を処理している間でも、エディターがサポートを提供できます。

型がなければ、それを達成するのはほぼ不可能です。
変数itemはリストitemsの要素の1つであることに注意してください。
それでも、エディターはそれがstrであることを認識し、それに対するサポートを提供します。
タプルとセット¶
tupleとsetを宣言する場合も同様です。
def process_items(items_t: tuple[int, int, str], items_s: set[bytes]):
return items_t, items_s
from typing import Set, Tuple
def process_items(items_t: Tuple[int, int, str], items_s: Set[bytes]):
return items_t, items_s
これは次のことを意味します
- 変数
items_tは、int、別のint、およびstrの3つの項目を持つtupleです。 - 変数
items_sはsetであり、その各項目はbytes型です。
辞書¶
dictを定義するには、カンマで区切られた2つの型パラメーターを渡します。
最初の型パラメーターはdictのキー用です。
2番目の型パラメーターはdictの値用です。
def process_items(prices: dict[str, float]):
for item_name, item_price in prices.items():
print(item_name)
print(item_price)
from typing import Dict
def process_items(prices: Dict[str, float]):
for item_name, item_price in prices.items():
print(item_name)
print(item_price)
これは次のことを意味します
- 変数
pricesはdictです。- この
dictのキーはstr型です(例えば、各アイテムの名前)。 - この
dictの値はfloat型です(例えば、各アイテムの価格)。
- この
ユニオン¶
変数がいくつかの型のいずれかであることを宣言できます。例えば、intまたはstr。
Python 3.6以降(Python 3.10を含む)では、typingモジュールのUnion型を使用し、角括弧内に受け入れる可能性のある型を記述できます。
Python 3.10には、垂直バー(|)で区切られた可能性のある型を記述できる新しい構文もあります。
def process_item(item: int | str):
print(item)
from typing import Union
def process_item(item: Union[int, str]):
print(item)
どちらの場合も、これはitemがintまたはstrである可能性があることを意味します。
Noneの可能性¶
値がstrのような型を持つ可能性があるが、Noneである可能性もあると宣言できます。
Python 3.6以降(Python 3.10を含む)では、typingモジュールからOptionalをインポートして使用することで宣言できます。
from typing import Optional
def say_hi(name: Optional[str] = None):
if name is not None:
print(f"Hey {name}!")
else:
print("Hello World")
単にstrではなくOptional[str]を使用すると、値が常にstrであると仮定している場合に、実際にはNoneである可能性もあるというエラーをエディターが検出するのに役立ちます。
Optional[Something]は実際にはUnion[Something, None]のショートカットであり、同等です。
これはPython 3.10ではSomething | Noneを使用できることも意味します。
def say_hi(name: str | None = None):
if name is not None:
print(f"Hey {name}!")
else:
print("Hello World")
from typing import Optional
def say_hi(name: Optional[str] = None):
if name is not None:
print(f"Hey {name}!")
else:
print("Hello World")
from typing import Union
def say_hi(name: Union[str, None] = None):
if name is not None:
print(f"Hey {name}!")
else:
print("Hello World")
UnionまたはOptionalを使用する¶
Python 3.10より前のバージョンを使用している場合、私の非常に主観的な視点からのヒントがあります。
- 🚨
Optional[SomeType]の使用は避けてください。 - 代わりに ✨
Union[SomeType, None]を使用してください ✨。
両者は同等であり、内部的には同じですが、OptionalではなくUnionをお勧めします。なぜなら、「optional」という言葉は値がオプションであることを暗示するように見えますが、実際には「Noneになりうる」という意味であり、オプションではなく必須である場合でもです。
Union[SomeType, None]の方が、それが何を意味するかについてより明確だと思います。
これは単に言葉や名前に関するものです。しかし、これらの言葉は、あなたやあなたのチームメイトがコードについてどのように考えるかに影響を与える可能性があります。
例として、この関数を見てみましょう。
from typing import Optional
def say_hi(name: Optional[str]):
print(f"Hey {name}!")
🤓 その他のバージョンとバリアント
def say_hi(name: str | None):
print(f"Hey {name}!")
パラメータnameはOptional[str]と定義されていますが、オプションではありません。パラメータなしで関数を呼び出すことはできません。
say_hi() # Oh, no, this throws an error! 😱
nameパラメータはデフォルト値がないため、依然として必須(オプションではない)です。それでも、nameはNoneを値として受け入れます。
say_hi(name=None) # This works, None is valid 🎉
良いニュースは、Python 3.10になると、型の結合を定義するために単に|を使用できるので、これについて心配する必要がなくなることです。
def say_hi(name: str | None):
print(f"Hey {name}!")
🤓 その他のバージョンとバリアント
from typing import Optional
def say_hi(name: Optional[str]):
print(f"Hey {name}!")
そうすれば、OptionalやUnionのような名前について心配する必要もありません。😎
ジェネリック型¶
角括弧内に型パラメーターを取るこれらの型は、ジェネリック型またはジェネリクスと呼ばれます。例えば、
ジェネリクスとして(角括弧と内部の型と共に)同じ組み込み型を使用できます。
listtuplesetdict
そして、Python 3.8と同様に、typingモジュールから
ユニオンOptional(Python 3.8と同じ)- ...その他。
Python 3.10では、ジェネリックなUnionやOptionalを使用する代わりに、垂直バー(|)を使用して型のユニオンを宣言できます。これははるかに優れていてシンプルです。
ジェネリクスとして(角括弧と内部の型と共に)同じ組み込み型を使用できます。
listtuplesetdict
そして、Python 3.8と同様に、typingモジュールから
ユニオンオプション- ...その他。
リストタプルセット辞書ユニオンオプション- ...その他。
型としてのクラス¶
クラスを変数の型として宣言することもできます。
名前を持つPersonクラスがあるとしましょう。
class Person:
def __init__(self, name: str):
self.name = name
def get_person_name(one_person: Person):
return one_person.name
次に、変数をPerson型として宣言できます。
class Person:
def __init__(self, name: str):
self.name = name
def get_person_name(one_person: Person):
return one_person.name
そして、再び、すべてのエディターサポートが得られます。

これは「one_personがPersonクラスのインスタンスである」ことを意味することに注意してください。
これは「one_personがPersonというクラスである」という意味ではありません。
Pydanticモデル¶
Pydanticはデータ検証を実行するためのPythonライブラリです。
データを属性を持つクラスとして「形状」を宣言します。
そして、各属性には型があります。
次に、そのクラスのインスタンスをいくつかの値で作成すると、値が検証され、適切な型に変換され(該当する場合)、すべてのデータを含むオブジェクトが提供されます。
そして、その結果のオブジェクトですべてのエディターサポートが得られます。
Pydantic公式ドキュメントからの例
from datetime import datetime
from pydantic import BaseModel
class User(BaseModel):
id: int
name: str = "John Doe"
signup_ts: datetime | None = None
friends: list[int] = []
external_data = {
"id": "123",
"signup_ts": "2017-06-01 12:22",
"friends": [1, "2", b"3"],
}
user = User(**external_data)
print(user)
# > User id=123 name='John Doe' signup_ts=datetime.datetime(2017, 6, 1, 12, 22) friends=[1, 2, 3]
print(user.id)
# > 123
from datetime import datetime
from typing import Union
from pydantic import BaseModel
class User(BaseModel):
id: int
name: str = "John Doe"
signup_ts: Union[datetime, None] = None
friends: list[int] = []
external_data = {
"id": "123",
"signup_ts": "2017-06-01 12:22",
"friends": [1, "2", b"3"],
}
user = User(**external_data)
print(user)
# > User id=123 name='John Doe' signup_ts=datetime.datetime(2017, 6, 1, 12, 22) friends=[1, 2, 3]
print(user.id)
# > 123
from datetime import datetime
from typing import List, Union
from pydantic import BaseModel
class User(BaseModel):
id: int
name: str = "John Doe"
signup_ts: Union[datetime, None] = None
friends: List[int] = []
external_data = {
"id": "123",
"signup_ts": "2017-06-01 12:22",
"friends": [1, "2", b"3"],
}
user = User(**external_data)
print(user)
# > User id=123 name='John Doe' signup_ts=datetime.datetime(2017, 6, 1, 12, 22) friends=[1, 2, 3]
print(user.id)
# > 123
情報
Pydanticの詳細については、そのドキュメントを確認してください。
FastAPIはすべてPydanticに基づいています。
これらすべてを実際に使用する方法については、チュートリアル - ユーザーガイドでさらに詳しく説明します。
ヒント
Pydanticには、デフォルト値なしでOptionalまたはUnion[Something, None]を使用した場合に特別な動作があります。必須のオプションフィールドに関するPydanticドキュメントで詳細を読むことができます。
メタデータアノテーション付き型ヒント¶
Pythonには、Annotatedを使用してこれらの型ヒントに追加のメタデータを配置できる機能もあります。
Python 3.9では、Annotatedは標準ライブラリの一部であるため、typingからインポートできます。
from typing import Annotated
def say_hello(name: Annotated[str, "this is just metadata"]) -> str:
return f"Hello {name}"
Python 3.9より前のバージョンでは、typing_extensionsからAnnotatedをインポートします。
これはFastAPIと共にすでにインストールされています。
from typing_extensions import Annotated
def say_hello(name: Annotated[str, "this is just metadata"]) -> str:
return f"Hello {name}"
Python自体は、このAnnotatedに対して何も行いません。エディターや他のツールにとって、型は依然としてstrです。
しかし、Annotatedのこのスペースを使用して、アプリケーションの動作方法に関する追加のメタデータをFastAPIに提供できます。
覚えておくべき重要なことは、Annotatedに渡す最初の型パラメーターが実際の型であるということです。残りは、他のツール用の単なるメタデータです。
今のところ、Annotatedが存在し、それが標準Pythonであることを知っているだけで十分です。😎
後で、それがどれほど強力であるかを確認できます。
ヒント
これが標準Pythonであるという事実は、エディターで、コードを分析およびリファクタリングするために使用するツールで、可能な限り最高の開発者エクスペリエンスを依然として得られることを意味します。✨
そして、あなたのコードが他の多くのPythonツールやライブラリと非常に互換性があることも意味します。🚀
FastAPIにおける型ヒント¶
FastAPIはこれらの型ヒントを利用していくつかのことを行います。
FastAPIで型ヒントを使用してパラメータを宣言すると、次のものが得られます。
- エディターのサポート.
- 型チェック.
...そしてFastAPIは同じ宣言を使用して
- 要件の定義: リクエストパスパラメータ、クエリパラメータ、ヘッダー、ボディ、依存関係などから。
- データの変換: リクエストから必要な型へ。
- データの検証: 各リクエストから送られてくるデータ。
- データが無効な場合にクライアントに返される自動エラーを生成します。
- OpenAPIを使用してAPIをドキュメント化します。
- これはその後、自動インタラクティブドキュメントユーザーインターフェースによって使用されます。
これはすべて抽象的に聞こえるかもしれません。心配しないでください。チュートリアル - ユーザーガイドでこれらすべてを実際に見ていきます。
重要なのは、標準のPython型を(追加のクラス、デコレーターなどを追加する代わりに)単一の場所で使用することで、FastAPIが多くの作業を代行してくれるということです。
情報
すでにすべてのチュートリアルを終えて、型についてさらに詳しく知るために戻ってきた場合は、mypyの「チートシート」が良いリソースです。