コンテンツにスキップ

Pythonの型の紹介

Python 3.6以降 では「型ヒント」オプションがサポートされています。

これらの "型ヒント" は変数のを宣言することができる新しい構文です。(Python 3.6以降)

変数に型を宣言することでエディターやツールがより良いサポートを提供することができます。

ここではPythonの型ヒントについての クイックチュートリアル/リフレッシュ で、FastAPIでそれらを使用するために必要な最低限のことだけをカバーしています。...実際には本当に少ないです。

FastAPI はすべてこれらの型ヒントに基づいており、多くの強みと利点を与えてくれます。

しかしたとえまったく FastAPI を使用しない場合でも、それらについて少し学ぶことで利点を得ることができるでしょう。

備考

もしあなたが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_namelast_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を押すと補完が実行されます。

しかし、悲しいことに、これはなんの役にも立ちません:

型の追加

先ほどのコードから一行変更してみましょう。

以下の関数のパラメータ部分を:

    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

エディタは変数の型を知っているので、補完だけでなく、エラーチェックをすることもできます。

これでagestr(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の標準的な型すべてを宣言することができます。

例えば、以下を使用可能です:

  • int
  • float
  • bool
  • bytes
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

型パラメータを持つジェネリック型

データ構造の中には、dictlistset、そしてtupleのように他の値を含むことができるものがあります。また内部の値も独自の型を持つことができます。

これらの型や内部の型を宣言するには、Pythonの標準モジュールtypingを使用します。

これらの型ヒントをサポートするために特別に存在しています。

List

例えば、strlistの変数を定義してみましょう。

typingからListをインポートします(大文字のLを含む):

from typing import List


def process_items(items: List[str]):
    for item in items:
        print(item)
🤓 Other versions and variants
def process_items(items: list[str]):
    for item in items:
        print(item)

同じようにコロン(:)の構文で変数を宣言します。

型として、Listを入力します。

リストはいくつかの内部の型を含む型なので、それらを角括弧で囲んでいます。

from typing import List


def process_items(items: List[str]):
    for item in items:
        print(item)
🤓 Other versions and variants
def process_items(items: list[str]):
    for item in items:
        print(item)

豆知識

角括弧内の内部の型は「型パラメータ」と呼ばれています。

この場合、strListに渡される型パラメータです。

つまり: 変数itemslistであり、このリストの各項目はstrです。

そうすることで、エディタはリストの項目を処理している間にもサポートを提供できます。

タイプがなければ、それはほぼ不可能です。

変数itemはリストitemsの要素の一つであることに注意してください。

それでも、エディタはそれがstrであることを知っていて、そのためのサポートを提供しています。

TupleSet

tuplesetの宣言も同様です:

from typing import Set, Tuple


def process_items(items_t: Tuple[int, int, str], items_s: Set[bytes]):
    return items_t, items_s
🤓 Other versions and variants
def process_items(items_t: tuple[int, int, str], items_s: set[bytes]):
    return items_t, items_s

つまり:

  • 変数items_tintintstrの3つの項目を持つtupleです

  • 変数items_sはそれぞれの項目がbytes型であるsetです。

Dict

dictを宣言するためには、カンマ区切りで2つの型パラメータを渡します。

最初の型パラメータはdictのキーです。

2番目の型パラメータはdictの値です。

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)
🤓 Other versions and variants
def process_items(prices: dict[str, float]):
    for item_name, item_price in prices.items():
        print(item_name)
        print(item_price)

つまり:

  • 変数pricesdictであり:
    • このdictのキーはstr型です。(つまり、各項目の名前)
    • このdictの値はfloat型です。(つまり、各項目の価格)

Optional

また、Optionalを使用して、変数がstrのような型を持つことを宣言することもできますが、それは「オプション」であり、Noneにすることもできます。

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である可能性があるエラーを検出するのに役立ちます。

ジェネリック型

以下のように角括弧で型パラメータを取る型を:

  • List
  • Tuple
  • Set
  • Dict
  • Optional
  • ...など

ジェネリック型 または ジェネリクス と呼びます。

型としてのクラス

変数の型としてクラスを宣言することもできます。

例えば、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

そして、再び、すべてのエディタのサポートを得ることができます:

Pydanticのモデル

Pydantic はデータ検証を行うためのPythonライブラリです。

データの「形」を属性付きのクラスとして宣言します。

そして、それぞれの属性は型を持ちます。

さらに、いくつかの値を持つクラスのインスタンスを作成すると、その値を検証し、適切な型に変換して(もしそうであれば)全てのデータを持つオブジェクトを提供してくれます。

また、その結果のオブジェクトですべてのエディタのサポートを受けることができます。

Pydanticの公式ドキュメントから引用:

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
🤓 Other versions and variants
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

情報

Pydanticについてより学びたい方はドキュメントを参照してください.

FastAPI はすべてPydanticをベースにしています。

すべてのことはチュートリアル - ユーザーガイドで実際に見ることができます。

FastAPIでの型ヒント

FastAPI はこれらの型ヒントを利用していくつかのことを行います。

FastAPI では型ヒントを使って型パラメータを宣言すると以下のものが得られます:

  • エディタサポート.
  • 型チェック.

...そして FastAPI は同じように宣言をすると、以下のことを行います:

  • 要件の定義: リクエストパスパラメータ、クエリパラメータ、ヘッダー、ボディ、依存関係などから要件を定義します。
  • データの変換: リクエストのデータを必要な型に変換します。
  • データの検証: リクエストごとに:
    • データが無効な場合にクライアントに返される 自動エラー を生成します。
  • ドキュメント OpenAPIを使用したAPI:
    • 自動的に対話型ドキュメントのユーザーインターフェイスで使用されます。

すべてが抽象的に聞こえるかもしれません。心配しないでください。 この全ての動作は チュートリアル - ユーザーガイドで見ることができます。

重要なのは、Pythonの標準的な型を使うことで、(クラスやデコレータなどを追加するのではなく)1つの場所で FastAPI が多くの作業を代わりにやってくれているということです。

情報

すでにすべてのチュートリアルを終えて、型についての詳細を見るためにこのページに戻ってきた場合は、mypyのチートシートを参照してください