Pythonの型指定のやり方【型ヒント, 3.10以降】
- 作成日: 2023-07-10
- 更新日: 2023-12-24
- カテゴリ: Python
Pythonの型指定のやり方
最近のPythonは型指定に力を入れていてどんどんバージョンアップされています。
もともとPythonには型指定などなく、かなり自由な記法だったのですが、それが不便だと言う意見があり型指定の機能が盛り込まれるようになったのではないかと推測できます。
型指定についてはtyping
モジュールに機能がまとめられていますが、このモジュールはかなり仕様が複雑です。
なぜシンプルなPythonにここまで型をこじつけようとするのかと言うと、そういう需要があるからですが、正直ここまで仕様が膨れ上がっていると覚えるのも大変かと思います。
この記事では最近のPythonの型指定のやり方を解説します。
できるだけ簡単に解説することを目指します。
関連記事
Djangoでオブジェクトを一括作成・更新【bulk_create, bulk_update】
DjangoのModel.objects.filter()の使い方【QuerySet】
Djangoのmodelのcreate()の使い方【Python】
Django入門: ルートの設定 ~ 簡単な一行掲示板アプリを作る その4【Windows10】
NumPyのappend()の使い方: 配列の末尾に要素を追加
Numpyのarangeの使い方: 指定範囲の数列を生成する
Python3でYoutube Data APIを使ってキーワード検索する
PythonからC言語(my.puts)を呼び出して実行する
型ヒント
変数には型ヒントを指定できます。
x: int = 1
y: str = 'hello'
コロン(:
)のあとのint
やstr
が型ヒントです。
関数の引数や返り値にも指定できます。
def func(x: int, y: str) -> str:
return x * y
print(func(10, 'hello'))
# hellohellohellohellohellohellohellohellohellohello
上記の場合、-> str
というのが返り値の型ヒントです。
これらの型ヒントには強制力はなく、実行時に型チェックはされません。
型チェックをしたい場合はmypy
などを使います。
mypyによる型チェック
mypy
をインストールします。
$ pip install mypy
型チェックをしたいファイルをmypy
で実行します。
$ mypy main.py
型指定に問題が無ければSuccess
と表示されます。
Success: no issues found in 1 source file
問題がある場合は以下のようなエラーになります。
main.py:5: error: Argument 1 to "MyNumber" has incompatible type "int"; expected "Number" [arg-type]
Found 1 error in 1 file (checked 1 source file)
Union(aまたはb)
Python3.10より前はaまたはb
という型を表現するときはUnion
を使っていました。
これは
from typing import Union
x: Union[int, str] = 1
上記のようなコードになります。
Union[int, str]
というのは「int
かstr
かのどちらか」という意味の型ヒントになります。
Python3.10以降は次のような書き方ができるようになりました。
x: int | str = 1
リスト、タプル、辞書の型ヒント
リストやタプル、辞書については以下のように型ヒントを書けます。
x: list[int] = [1, 2]
y: tuple[float, float] = (1.2, 3.4)
z: dict[str, int | str] = {'a': 1, 'b': 'hello'}
list[int]
のint
は複数可ですが、tuple[float, float]
はタプルの値が2つまでになります。
dict
の場合は値はint | str
でint
かstr
のどちらかという指定になります。
型エイリアス
型のエイリアス(別名)です。
たとえばfloat
を持つlist
を型として定義したい場合は
Vector = list[float]
x: Vector = [1.2, 2.3]
こういう感じでVector
を定義します。
またTypeAlias
を使う場合は
from typing import TypeAlias
Vector: TypeAlias = list[float]
のように定義します。
新しい型の定義(NewType)
新しい型を定義したい場合はNewType
を使います。
from typing import NewType
Number = NewType('Number', int)
x = Number(123)
print(x) # 123
上記の場合、Number
という型を新しく定義しています。
Number
型の実体はint
型になっています。
NewType
した型からさらに型を定義することも可能です。
from typing import NewType
Number = NewType('Number', int)
MyNumber = NewType('MyNumber', Number)
x = MyNumber(Number(123))
print(x) # 123
呼び出し可能なオブジェクトの型ヒント
関数のように呼び出しが可能なオブジェクトにはCallable
という型ヒントを付けられます。
from collections.abc import Callable
def func(x: int, y: str) -> str:
return x * y
fn: Callable[[int, str], str] = func
このCallable
は何ともわかりづらいですが、以下のような書式になります。
Callable[[第1引数の型, 第2引数の型, ...], 返り値の型]
TypeVar
型変数というのでジェネリクスなコードを書くことができます。
from typing import TypeVar
T = TypeVar('T') # 型変数のTを定義
def func(l: list[T]) -> T:
return l[0]
print(func([1, 2, 3])) # 1
この型変数はNewType
とは区別されます。
この違いは以下のコードを見るとわかりやすいと思います。
from typing import NewType
T = NewType('T', int) # 型変数のTを定義
def func(l: list[T]) -> T:
return l[0]
print(func([1, 2, 3])) # 1
上記のコードをmypy
にかけると以下のエラーになります。
main.py:8: error: List item 0 has incompatible type "int"; expected "T" [list-item]
main.py:8: error: List item 1 has incompatible type "int"; expected "T" [list-item]
main.py:8: error: List item 2 has incompatible type "int"; expected "T" [list-item]
Found 3 errors in 1 file (checked 1 source file)
このエラーの意味するところはNewType
はint
とは別の型として区別されていることです。
一方、TypeVar
の場合はint
を許容しています。
NewType
はmypy
上で厳密に型判定されますが、TypeVar
はジェネリクス的に判定されるということだと思います。
TypeVar
も型を指定できますが、これは許容する型を制限するために指定します。
from typing import TypeVar
T = TypeVar('T', int, str) # intまたはstrを許容
def func(l: list[T]) -> T:
return l[0]
print(func([1, 2, 3])) # 1
print(func(['a', 'b', 'c'])) # a
# print(func([1, 'a'])) # 複合はエラーになる
# main.py:10: error: Value of type variable "T" of "func" cannot be "object" [type-var]
# print(func([1.2])) # 許容していない型
# main.py:14: error: Value of type variable "T" of "func" cannot be "float" [type-var]
Any型
Anyはなんでもありな型です。
from typing import Any
a: Any = None
a = [] # OK
a = 2 # OK
s: str = ''
s = a # OK
おわりに
typing
にはこの他にもたくさんの機能があり、それらを全部紹介するのは無理です。
今回は目立っている機能を紹介しました。
なにか参考になれば幸いです。
🦝 < 頭がフットーしそうだよぉ!
🦝 < 型に縛られるぅ!