# Pythonの型の紹介 { #python-types-intro }

Python にはオプションの「型ヒント」（「型アノテーション」とも呼ばれます）がサポートされています。

これらの **「型ヒント」** やアノテーションは、変数の<dfn title="例えば: str、int、float、bool">型</dfn>を宣言できる特別な構文です。

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

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

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

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

/// note | 備考

もしあなたが Python の専門家で、すでに型ヒントについてすべて知っているのであれば、次の章まで読み飛ばしてください。

///

## 動機 { #motivation }

簡単な例から始めてみましょう:

{* ../../docs_src/python_types/tutorial001_py310.py *}

このプログラムを呼び出すと、以下が出力されます:

```
John Doe
```

この関数は以下のようなことを行います:

* `first_name` と `last_name` を取得します。
* `title()` を用いて、それぞれの最初の文字を大文字に変換します。
* 真ん中にスペースを入れて<dfn title="1つにまとめます。片方の内容をもう片方の後ろに続けます。">連結</dfn>します。

{* ../../docs_src/python_types/tutorial001_py310.py hl[2] *}

### 編集 { #edit-it }

これはとても簡単なプログラムです。

しかし、今、あなたがそれを一から書いていたと想像してみてください。

パラメータの準備ができていたら、そのとき、関数の定義を始めていたことでしょう...

しかし、そうすると「最初の文字を大文字に変換するあのメソッド」を呼び出す必要があります。

それは `upper` でしたか？`uppercase` でしたか？`first_uppercase`？`capitalize`？

そして、古くからプログラマーの友人であるエディタで自動補完を試してみます。

関数の最初のパラメータ `first_name` を入力し、ドット（`.`）を入力してから、`Ctrl+Space` を押すと補完が実行されます。

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

<img src="/img/python-types/image01.png">

### 型の追加 { #add-types }

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

関数のパラメータである次の断片を、以下から:

```Python
    first_name, last_name
```

以下へ変更します:

```Python
    first_name: str, last_name: str
```

これだけです。

それが「型ヒント」です:

{* ../../docs_src/python_types/tutorial002_py310.py hl[1] *}

これは、以下のようにデフォルト値を宣言するのと同じではありません:

```Python
    first_name="john", last_name="doe"
```

それとは別物です。

イコール（`=`）ではなく、コロン（`:`）を使用します。

そして、通常、型ヒントを追加しても、それらがない状態と起こることは何も変わりません。

しかし今、あなたが再びその関数を作成している最中に、型ヒントを使っていると想像してみてください。

同じタイミングで `Ctrl+Space` で自動補完を実行すると、以下のようになります:

<img src="/img/python-types/image02.png">

これであれば、あなたは「ベルを鳴らす」ものを見つけるまで、オプションを見てスクロールできます:

<img src="/img/python-types/image03.png">

## より強い動機 { #more-motivation }

この関数を見てください。すでに型ヒントを持っています:

{* ../../docs_src/python_types/tutorial003_py310.py hl[1] *}

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

<img src="/img/python-types/image04.png">

これで `age` を `str(age)` で文字列に変換して修正する必要があることがわかります:

{* ../../docs_src/python_types/tutorial004_py310.py hl[2] *}

## 型の宣言 { #declaring-types }

型ヒントを宣言する主な場所を見てきました。関数のパラメータです。

これは **FastAPI** で使用する主な場所でもあります。

### 単純な型 { #simple-types }

`str` だけでなく、Python の標準的な型すべてを宣言できます。

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

* `int`
* `float`
* `bool`
* `bytes`

{* ../../docs_src/python_types/tutorial005_py310.py hl[1] *}

### `typing` モジュール { #typing-module }

いくつかの追加のユースケースでは、標準ライブラリの `typing` モジュールから何かをインポートする必要があるかもしれません。例えば「任意の型」を受け付けることを宣言したい場合、`typing` の `Any` を使えます:

```python
from typing import Any


def some_function(data: Any):
    print(data)
```

### ジェネリック型 { #generic-types }

一部の型は、角括弧内で「型パラメータ」を受け取り、内部の型を定義できます。例えば「文字列のリスト」は `list[str]` として宣言します。

このように型パラメータを取れる型は **Generic types**（ジェネリクス）と呼ばれます。

次の組み込み型をジェネリクスとして（角括弧と内部の型で）使えます:

* `list`
* `tuple`
* `set`
* `dict`

#### List { #list }

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

同じコロン（`:`）の構文で変数を宣言します。

型として、`list` を指定します。

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

{* ../../docs_src/python_types/tutorial006_py310.py hl[1] *}

/// info | 情報

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

この場合、`str` は `list` に渡される型パラメータです。

///

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

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

<img src="/img/python-types/image05.png">

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

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

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

#### Tuple と Set { #tuple-and-set }

`tuple` と `set` の宣言も同様です:

{* ../../docs_src/python_types/tutorial007_py310.py hl[1] *}

つまり:

* 変数 `items_t` は `int`、別の `int`、`str` の 3 つの項目を持つ `tuple` です。
* 変数 `items_s` は `set` であり、その各項目は `bytes` 型です。

#### Dict { #dict }

`dict` を定義するには、カンマ区切りで 2 つの型パラメータを渡します。

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

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

{* ../../docs_src/python_types/tutorial008_py310.py hl[1] *}

つまり:

* 変数 `prices` は `dict` です:
    * この `dict` のキーは `str` 型です（例えば、各項目の名前）。
    * この `dict` の値は `float` 型です（例えば、各項目の価格）。

#### Union { #union }

変数が **複数の型のいずれか** になり得ることを宣言できます。例えば、`int` または `str` です。

それを定義するには、両方の型を区切るために <dfn title="「ビット単位の OR 演算子」とも呼ばれますが、ここでの意味とは関係ありません。">縦棒（`|`）</dfn> を使います。

これは「ユニオン（union）」と呼ばれます。変数がそれら 2 つの型の集合の和集合のいずれかになり得るからです。

```Python hl_lines="1"
{!> ../../docs_src/python_types/tutorial008b_py310.py!}
```

これは `item` が `int` または `str` になり得ることを意味します。

#### `None` の可能性 { #possibly-none }

値が `str` のような型を持つ可能性がある一方で、`None` にもなり得ることを宣言できます。

//// tab | Python 3.10+

```Python hl_lines="1"
{!> ../../docs_src/python_types/tutorial009_py310.py!}
```

////

ただの `str` の代わりに `str | None` を使用することで、値が常に `str` であると仮定しているときに、実際には `None` である可能性もあるというエラーをエディタが検出するのに役立ちます。

### 型としてのクラス { #classes-as-types }

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

名前を持つ `Person` クラスがあるとしましょう:

{* ../../docs_src/python_types/tutorial010_py310.py hl[1:3] *}

変数を `Person` 型として宣言できます:

{* ../../docs_src/python_types/tutorial010_py310.py hl[6] *}

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

<img src="/img/python-types/image06.png">

これは「`one_person` はクラス `Person` の **インスタンス** である」ことを意味します。

「`one_person` は `Person` という名前の **クラス** である」という意味ではありません。

## Pydantic のモデル { #pydantic-models }

[Pydantic](https://docs.pydantic.dev/) はデータ検証を行うための Python ライブラリです。

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

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

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

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

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

{* ../../docs_src/python_types/tutorial011_py310.py *}

/// info | 情報

[ Pydantic の詳細はドキュメントを参照してください](https://docs.pydantic.dev/)。

///

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

すべてのことは [チュートリアル - ユーザーガイド](tutorial/index.md) で実際に見ることができます。

## メタデータアノテーション付き型ヒント { #type-hints-with-metadata-annotations }

Python には、`Annotated` を使って型ヒントに **追加の <dfn title="データに関するデータ。この場合は型に関する情報（例えば説明）。">メタデータ</dfn>** を付与できる機能もあります。

`Annotated` は `typing` からインポートできます。

{* ../../docs_src/python_types/tutorial013_py310.py hl[1,4] *}

Python 自体は、この `Annotated` で何かをするわけではありません。また、エディタや他のツールにとっても、型は依然として `str` です。

しかし、`Annotated` 内のこのスペースを使って、アプリケーションをどのように動作させたいかについての追加メタデータを **FastAPI** に提供できます。

覚えておくべき重要な点は、`Annotated` に渡す **最初の「型パラメータ」** が **実際の型** であることです。残りは、他のツール向けのメタデータにすぎません。

今のところは、`Annotated` が存在し、それが標準の Python であることを知っておけば十分です。😎

後で、これがどれほど **強力** になり得るかを見ることになります。

/// tip | 豆知識

これが **標準の Python** であるという事実は、エディタで、使用しているツール（コードの解析やリファクタリングなど）とともに、**可能な限り最高の開発体験** が得られることを意味します。 ✨

また、あなたのコードが他の多くの Python ツールやライブラリとも非常に互換性が高いことも意味します。 🚀

///

## **FastAPI** での型ヒント { #type-hints-in-fastapi }

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

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

* **エディタサポート**。
* **型チェック**。

...そして **FastAPI** は同じ宣言を使って、以下のことを行います:

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

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

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

/// info | 情報

すでにすべてのチュートリアルを終えて、型についての詳細を見るためにこのページに戻ってきた場合は、良いリソースとして [`mypy` の「チートシート`](https://mypy.readthedocs.io/en/latest/cheat_sheet_py3.html) があります。

///
