今回はpythonで関数などを定義するときの
型ヒントについて解説していきます
この記事を読むべき方・・・
- Pythonを使用してプログラミングをしているエンジニアや開発者
- 型ヒントを使ってバグを減らしたい方
- 静的解析ツール(mypy)を導入したい方
型ヒントのメリット・デメリット
型ヒントとは、コードの定義時に型を明示する機能です
以下にその具体的な例を示します
具体例
# 型ヒントを使った関数
def add(a: int, b: int) -> int:
return a + b
# 使用例
result = add(5, 10)
print(result) # 出力: 15
上記の例では、add関数に型ヒントを付けることで
引数aとbが整数型(int)であり
戻り値も整数型であることを示しています
あくまでこの型を使用してと明示するだけです
メリット
- 可読性up: 型が明示されることで、コードの意図がわかりやすくなる
- バグの早期発見: 実行前に型の不一致によるバグを発見できる
- 自己文書化: コード自体がドキュメントとしての役割を果たす
- 保守性の向上: 型情報により、コードの変更や拡張がしやすくなる
デメリット
正直おおきなデメリットはありませんが
あえてあげるとすれば以下のような
マイナス要素があります
- コードが冗長になる: 型ヒントの追加でコード行数が増えることがある
- 修正コスト: 既存のコードに型ヒントを追加する場合、修正コストがかかる
- 実行時に影響しない: 型ヒントは静的解析のためで、実行時に型エラーを防ぐものではない
型ヒントの使用例
ここでは、型ヒントの具体的な使用例を3つ紹介します
例1. 引数・戻り値の型を指定する方法(整数型)
型ヒントを使って引数や戻り値の型を明示します
整数型
# 引数と戻り値に型ヒントを付けた関数
def add(a: int, b: int) -> int:
return a + b
# 使用例
result = add(5, 10)
print(result) # 出力: 15
この例では、
add関数の引数aとbに対してint型を指定し
戻り値もint型を指定しています
例2. リストや辞書を指定する方法
型ヒントはリストや辞書などの複雑なデータ構造にも適用できます。
リスト型
from typing import List
# リスト型の引数に型ヒントを付けた関数
def calculate_average(scores: List[float]) -> float:
return sum(scores) / len(scores)
# 使用例
average = calculate_average([85.5, 90.0, 78.5])
print(average) # 出力: 84.66666666666667
この例では
calculate_average関数がList[float]型を受け取り
リスト内の要素がすべてfloat型にすることを示しています
辞書型
from typing import Dict, List
# 辞書型の引数に型ヒントを付けた関数
def get_student_names(students: Dict[int, str]) -> List[str]:
return list(students.values())
# 使用例
names = get_student_names({1: "Alice", 2: "Bob", 3: "Charlie"})
print(names) # 出力: ['Alice', 'Bob', 'Charlie']
この例では
get_student_names関数がDict[int, str]型の辞書を受け取り
その値をリストとして返すことを示しています
例3. UnionやOptionalを使った複数の型を指定する方法
UnionやOptionalを使用することで
関数が複数の型を指定する場合や
Noneも許容することを示すことができます
Union
from typing import Union
# Unionを使って複数の型を許容する関数
def process_data(data: Union[int, float]) -> float:
return float(data) * 2
# 使用例
result1 = process_data(10) # int型
print(result1) # 出力: 20.0
result2 = process_data(10.0) # float型
print(result2) # 出力: 20.0
この例では
process_data関数がUnion[int, float]を使うことで
引数にint型またはfloat型を指定しています
Optional
from typing import Optional
# Optionalを使ってNoneを許容する関数
def greet_user(name: Optional[str] = None) -> str:
if name:
return f"Hello, {name}!"
return "Hello, Guest!"
# 使用例
result2 = greet_user()
print(result2) # 出力: Hello, Guest!
result3 = greet_user("Alice")
print(result3) # 出力: Hello, Alice!
この例では
greet_user関数がOptional[str]を使用して
Noneまたはstr型を指定しています
型チェックツール mypy の使用方法と設定方法
型チェックは
あくまで型はこれにしてねーと示すものであり
実行時のエラーを防ぐものではありません
mypyを使うとコードの実行前に
型のエラーを見つけることができます
ここでは、mypyの以下の点について解説します
- 基本的な使い方
- 主なオプションの説明
- 設定ファイルを使った型チェックの管理方法
mypy の基本的な使用方法
mypyはコマンドラインから簡単に使うことができます
チェックしたいPythonファイルに対して
以下のコマンドを実行します
mypy your_script.py
このコマンドを実行すると
your_script.pyの中の
型の不一致や誤りを検出できます
mypy の主なオプション
mypyには、型チェックをカスタマイズできる
さまざまなオプションがあります
たくさんのオプションがあるため
気になる方は以下をクリックしてみてください
mypyドキュメントも参考にしてみてください
- mypyのオプション一覧はこちらをクリック
- ※()内は易しい言葉での説明
- 基本オプション
–help
mypyの使い方やオプションの一覧を表示します
(mypyの使い方を確認するためのヘルプを表示)
–version
mypyのバージョン情報を表示します
(現在使っているmypyのバージョンを確認する)
–config-file FILE
指定した設定ファイルを使ってmypyを実行します
(カスタム設定を使うためのファイルを指定する)
- チェックモードオプション
–strict
すべての厳密なチェックオプションを有効にします
(可能な限り厳しくチェックするモードにする)
–ignore-missing-imports
存在しないインポートに対してエラーを無視します
(インポートエラーを無視する設定)
–allow-untyped-calls
型が指定されていない関数への呼び出しを許可します
(タイプのない関数呼び出しを許可する)
–allow-untyped-defs
型が指定されていない関数定義を許可します
(タイプがない関数定義を許可する)
–check-untyped-defs
型指定のない関数定義の内部もチェックします
(タイプがない関数の中もチェックする)
–disallow-untyped-calls
型指定のない関数への呼び出しを禁止します
(タイプのない関数呼び出しを禁止する)
–disallow-untyped-defs
型指定のない関数定義を禁止します
(タイプがない関数定義を禁止する)
–disallow-incomplete-defs
部分的に型指定がない関数定義を禁止します
(タイプが部分的に欠けている関数定義を禁止する)
- エラーと警告に関するオプション
–show-error-codes
エラーコードを表示します
(エラーの種類を示すコードを表示する)
–show-column-numbers
エラー位置の列番号を表示します
(エラーがどの列にあるかを示す)
–warn-unused-ignores
不要な# type: ignore`がある場合に警告を表示します
(必要ない無視コメントがあると警告する)
–warn-unreachable
到達不能なコードがある場合に警告します
(実行されないコードがあると警告する)
–warn-return-any
Any型を返す関数に対して警告を出します
(返り値がAny`の場合に警告する)
- 出力形式に関するオプション
–pretty
エラーメッセージを見やすい形式で表示します
(エラーメッセージを見やすくする)
–no-color-output
カラー出力を無効にします
(エラーメッセージを白黒で表示する)
–junit-xml
テスト結果をJUnit XML形式で出力します
(JUnit形式でテスト結果を出力する)
- パフォーマンスに関するオプション
–cache-dir DIR
キャッシュを保存するディレクトリを指定します
(キャッシュを保存する場所を指定する)
–no-incremental
インクリメンタルチェックを無効にします
(前回のチェック結果を使わず、全て再チェックする)
–follow-imports {normal,silent,skip,error}
インポートの処理方法を指定します(
ex)normal:通常のチェック、skip:インポートを無視
(インポートのチェック方法を指定する)
- その他のオプション
–install-types
型情報が不足しているパッケージのために必要な型ヒントパッケージを自動的にインストールします
(必要な型情報を自動でインストールする)
–namespace-packages
名前空間パッケージ(PEP 420`)をサポートします
(複数のパッケージにまたがる構成をサポートする)
–strict-equality
型が異なるオブジェクトの比較に警告を表示します
(異なる型の比較に警告する)
- 複数ファイルやディレクトリを指定する
FILE
型チェックするPythonファイルやディレクトリを指定します(複数指定可能)
(チェックするファイルやフォルダを指定する)
- カスタムプラグインの使用
–plugin MODULE
カスタム mypy` プラグインを指定します
(独自のチェックを追加するプラグインを指定する)
使い方はコマンドラインでmypyを実行するときに
mypy [オプション] [ファイル名]
って感じで使うよー
設定ファイルを使った型チェックの管理
mypyの設定をプロジェクトごとに一括管理するために
設定ファイルを使用できます
オプションを指定する必要がなくなるよー
設定ファイルの使用例を
解説しておきます
フォルダ構成
/your_project
|-- mypy.ini # ここにmypyのオプションを記述する
|-- your_script.py # 適当なPythonファイル
|-- another_script.py # 適当なPythonファイル2
ファイル内容: mypy.ini
mypy.iniに、mypyのオプションを記述します
[mypy]
ignore_missing_imports = True
disallow_untyped_defs = True
check_untyped_defs = True
mypyの実行
プロジェクトのすべてのPythonファイルに対してmypyを実行します
mypy.iniファイルに記載しているオプションが適用されます
以下にエラーがある場合・ない場合の
実行結果例を示します
# mypyの実行
mypy your_project/ # your_projectフォルダ内のすべてのPythonファイルをチェック
# 実行結果例(エラーなし)
Success: no issues found in 2 source files
# 実行結果例(エラーあり)
your_project/your_script.py:4: # your_script.pyファイルの4行目にエラーがある
error: Argument 2 to "add" has incompatible type "str"; expected "int" # add関数の2番目の引数がint型でない
Found 1 error in 1 file (checked 2 source files) # 1つのエラーが見つかりました
型チェックとmypyを使って
保守性や品質を向上させていきましょう!!!