Python3.10で採択された | 記号によるUnionの型アノテーションについて早速調べてみた（PEP604）

Python3.10.0のα版が公開されていました。

<blockquote class="twitter-tweet"><p lang="en" dir="ltr">Python 3.10.0a2 is now available for testing. The engines of the secret release manager machine have finished producing a new pre-release. Get it here: <a href="https://t.co/CmrqKoR4we">https://t.co/CmrqKoR4we</a>. This is an early developer preview of Python 3.10.</p>&mdash; Python Software Foundation (@ThePSF) <a href="https://twitter.com/ThePSF/status/1324936870820802560?ref_src=twsrc%5Etfw">November 7, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

[リリースノート](https://www.python.org/downloads/release/python-3100a2/)を見ていて、| 記号によるUnionとしての型アノテーションの書き方（[PEP604](https://www.python.org/dev/peps/pep-0604/)）が追加になっていたのでPython3.10.0をインストールしつつ詳しく調べてみました。

# typingのUnionやOptionalクラスのimportなどが不要になる

今まで複数の型になりうる値に関しては以下のようにUnionクラスをimportして使う必要がありました。

```py
from typing import Union

value: Union[int, str] = 10
```

また、変数や引数などでNoneもしくは他の型の値を取るといったケースではOptionalを同様にimportして使う必要がありました。

```py
from typing import Optional

value: Optional[int] = None
```

それが今後、以下のように`|`の記号を使うことで型アノテーションができるようになります。

```py
value: int|str = 100
```

importが不要になり楽になりますし、1行の文字数が多くなったりしないのでPEP8などの準拠が楽になります。

少し前に追加された、typingモジュールを使った`List[型]`の代わりに`list[型]`といったように書けるようになったのと同様に、型アノテーションがより楽になる正常進化的な感じでしょうか。

Optionalに関しても同様に`|`記号とNoneを使うことで、import無しで型アノテーションできるようになります。

```py
value: int|None = None
```

# 他と組み合わせるとぐぐっと記述がシンプルになる

たとえばキーに文字列、値にintもしくはfloatを受け付ける辞書に対して型アノテーションをしたいとします。旧来（Python3.8以前など）では以下のように書く必要がありました。

```py
from typing import Dict, Union

value: Dict[str, Union[int, float]] = {'price': 100}
```

それがPython3.10環境では以下のように書けるようになります（dictやlistで書けるようになったのは3.9からとなります）。
importが減る点も含め、行数も列数も（入れ子になったりせず）結構すっきりします。

```py
value: dict[str, int|float] = {'price': 100}
```

# もちろん引数や返却値などでも使える

前述のものは関数の引数や返却値でも同様に利用できます。

特に型アノテーションでの指定がリストや辞書などで入れ子になったりすると、複数の引数や返却値を持つ関数などで横に長くなったり見づらくなったりしがちだったものがシンプルな記述になります。

```py
def sample_func(
        value_1: int|str, value_2: dict[str, int|float],
        value_3: int|None=None) -> int|None:
    ...
```

# isinstanceやissubclassでも使えるようになる

型チェックで使われるisinstanceやissubclassに関して、複数の型を対象とする場合には以下のようにタプルを使う必要がありました。

```py
>>> value = 100
>>> print(isinstance(value, (int, str)))

True
```

今後はタプルの代わりに以下のように`|`記号を使って書くこともできるようになります。

```py
>>> value = 'apple'
>>> print(isinstance(value, str|int))

True
```

# Pylanceでの対応状況は・・・

今回の記事の内容はVS Code + Pylance + Kiteの環境を使っています。
（Pylanceについての記事 : [[Python]PylanceのVS Code拡張機能をさっそく使ってみた。](https://qiita.com/simonritchie/items/33ca57cdb5cb2a12ae16)）

マウスオーバー時などの型の表示はすでにちゃんと対応が入っていました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/228778/2b30f441-5b0d-8c5b-4189-48450f1d0015.png)

補完なども問題なく、複数の型に応じたものなどが表示されていました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/228778/e35f5b0d-6100-800f-c3b3-fc5ade47f913.png)

ただし、`|`記号の箇所ではPylanceでエラーと判定されていました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/228778/3491f71d-ad17-4051-9ad8-dff6e27f6247.png)

VS Code上でPython3.10.0のインタプリタを設定していてもこのエラーが出ます。まあこれは近いうちにPylanceのアップデートで修正してくださるでしょう。

# 参考サイト

- [Python 3.10.0a2 （リリースノート）](https://www.python.org/downloads/release/python-3100a2/)
- [PEP604](https://www.python.org/dev/peps/pep-0604/)