Python ValueError: invalid literal for int() の原因と解決方法【よくある落とし穴と実践的な対処法】

ValueError: invalid literal for int() with base 10: ‘…’ とは

Pythonで文字列を数値に変換しようとした際に遭遇するValueError: invalid literal for int() with base 10エラーは、特にユーザー入力やファイル読み込み、APIからのデータ処理で頻繁に発生します。このエラーは、数値として解釈できない文字列をint()関数に渡したときに発生し、プログラムの予期せぬ終了を引き起こすことがあります。

このエラーの核心は、「数値に見えない文字列を数値に変換しようとしている」点にあります。焦らず、入力値の型と内容をデバッグで確認することが解決への第一歩です。

エラーの発生パターン

このエラーは主に以下のようなケースで発生します。

パターン1: パターン1: ユーザー入力が数値ではない

# ユーザーからの入力を受け取る
user_input = input("数字を入力してください: ") # 例: 'abc' と入力

# 文字列を整数に変換しようとする
num = int(user_input)
print(f"入力された数字: {num}")

input()関数は常に文字列を返します。ユーザーが数字以外の文字列(例: ‘abc’)や空文字を入力した場合、int()関数はその文字列を10進数の数値として解釈できないため、ValueErrorが発生します。

# ユーザーからの入力を受け取る
user_input = input("数字を入力してください: ")

# 数値変換前にバリデーションまたはエラーハンドリングを行う
try:
    num = int(user_input)
    print(f"入力された数字: {num}")
except ValueError:
    print(f"エラー: '{user_input}' は有効な数字ではありません。")

# または、事前チェック
if user_input.isdigit(): # 正の整数のみをチェックする場合
    num = int(user_input)
    print(f"入力された数字: {num}")
else:
    print(f"エラー: '{user_input}' は有効な数字ではありません。")

パターン2: パターン2: ファイルから読み込んだデータに非数値が含まれる

# scores.txt の内容: 
# 100
# 95
# N/A
# 80

with open('scores.txt', 'r') as f:
    for line in f:
        # 各行を数値に変換しようとする
        score = int(line.strip())
        print(f"スコア: {score}")

ファイルから読み込んだデータは通常文字列として扱われます。特にCSVやログファイルなどでは、欠損値やエラーを示す文字列(例: ‘N/A’, ‘-‘)が数値の列に混入していることがあります。strip()で空白を除去しても、非数値文字列はint()で変換できません。

# scores.txt の内容: 
# 100
# 95
# N/A
# 80

with open('scores.txt', 'r') as f:
    for line in f:
        clean_line = line.strip()
        # 数値変換前にエラーハンドリングまたは条件分岐で対応
        try:
            score = int(clean_line)
            print(f"スコア: {score}")
        except ValueError:
            print(f"警告: '{clean_line}' は無効なスコアです。スキップします。")
            # またはデフォルト値を設定する: score = 0

パターン3: パターン3: APIレスポンスのデータ型不一致

import json

# APIからのレスポンスを想定 (status_codeが文字列)
api_response_str = '{"id": 101, "item_name": "Widget", "status_code": "200"}'
# または、status_codeが予期せず空文字やnullだった場合
# api_response_str = '{"id": 101, "item_name": "Widget", "status_code": ""}'

response_data = json.loads(api_response_str)

# status_codeを整数として使用したい
status_code_int = int(response_data['status_code'])
print(f"ステータスコード: {status_code_int}")

外部APIからのJSONレスポンスは、ドキュメントと異なるデータ型で値が返されることがあります。特に、数値と期待していたフィールドが文字列(例: ‘200’)として返されたり、空文字やnullで返されたりすると、そのままint()に渡すとValueErrorが発生します。

import json

api_response_str = '{"id": 101, "item_name": "Widget", "status_code": "200"}'
# api_response_str = '{"id": 101, "item_name": "Widget", "status_code": ""}'
# api_response_str = '{"id": 101, "item_name": "Widget", "status_code": null}'

response_data = json.loads(api_response_str)

status_code_raw = response_data.get('status_code')

try:
    # nullや空文字の場合はNoneになるため、int()に渡す前にチェック
    if status_code_raw is None or str(status_code_raw).strip() == '':
        status_code_int = 0 # デフォルト値など
        print(f"警告: ステータスコードが不正なため、デフォルト値 {status_code_int} を使用しました。")
    else:
        status_code_int = int(status_code_raw)
        print(f"ステータスコード: {status_code_int}")
except ValueError:
    print(f"エラー: '{status_code_raw}' は無効なステータスコードです。")
    status_code_int = -1 # エラー時の値など
このエラーはfloat()関数でも発生しますが、その場合はValueError: could not convert string to float: '...'というメッセージになります。基本的な考え方と対処法は同じです。

根本原因の特定方法

エラーが発生したら、まず{marker}int()関数に渡されている変数の値と型をprint()関数やデバッガで確認{/marker}しましょう。print(f"Value: {variable}, Type: {type(variable)}")のように出力することで、問題の原因(変数が期待する型や値ではないこと)を特定しやすくなります。

# エラーが発生しそうな場所の直前で変数をチェック
user_input = "abc"
# user_input = "123"

print(f"デバッグ情報: user_input = '{user_input}', type = {type(user_input)}")

try:
    num = int(user_input)
    print(f"変換された数字: {num}")
except ValueError as e:
    print(f"エラーを捕捉しました: {e}")

防止策とベストプラクティス

数値変換前には、{marker}入力値が数値として有効であるかを事前にチェック{/marker}するか、try-exceptブロックでエラーを捕捉してプログラムが停止しないようにすることが最も効果的な予防策です。文字列のメソッド(isdigit()など)や正規表現を使って数値形式を検証することも有効です。

# 予防策1: isdigit() で事前チェック
user_input = input("数字を入力してください: ")
if user_input.isdigit(): # 正の整数のみを判定
    num = int(user_input)
    print(f"入力された数字: {num}")
else:
    print(f"エラー: '{user_input}' は有効な数字ではありません。")

# 予防策2: try-except ブロックでエラーハンドリング
def safe_int_conversion(value):
    try:
        return int(value)
    except ValueError:
        return None # 変換失敗時はNoneを返すなど

input_value = "not_a_number"
converted_num = safe_int_conversion(input_value)
if converted_num is not None:
    print(f"変換成功: {converted_num}")
else:
    print(f"変換失敗: '{input_value}' は数値ではありませんでした。")
isdigit()は文字列が全て数字で構成されているか(正の整数)をチェックします。負の数や浮動小数点数には対応しないため、より柔軟なチェックが必要な場合は正規表現やtry-exceptを使いましょう。

よくある質問(FAQ)

Q
int()の代わりにfloat()を使ってもこのエラーは出ますか?
A

はい、float()関数でも数値として解釈できない文字列を渡すとValueErrorが発生します。メッセージはValueError: could not convert string to float: '...'となりますが、基本的な対処法は同じです。

Q
本番環境でだけこのエラーが発生するのですが、原因は何が考えられますか?
A

本番環境特有の原因として、ユーザー入力の多様性、外部システム(APIなど)からの予期せぬデータ形式、あるいは環境変数の設定ミスが考えられます。開発環境と本番環境でデータソースやロケール設定が異なる場合もあります。

Q
Django REST Framework (DRF) でAPIを開発しているのですが、このエラーをどう防げばいいですか?
A

DRFではシリアライザのフィールドバリデーションを活用しましょう。例えばserializers.IntegerField()を使えば、非整数値が渡された場合に自動的にバリデーションエラーを発生させ、適切なレスポンスを返すことができます。

Q
try-exceptでエラーを捕捉した場合、ユーザーにはどのようなエラーメッセージを返すべきですか?
A

ユーザーには{marker}技術的なエラーメッセージではなく、何が問題だったのかを具体的に伝える、分かりやすいメッセージ{/marker}を返すようにしましょう。例えば「入力された値は数値ではありません。半角数字で入力してください。」といった形です。

Q
Pythonのint()関数は、なぜ基数を指定する必要があるのですか?
A

int()関数は、デフォルトで基数10(10進数)を想定しますが、2進数('0b101')、8進数('0o12')、16進数('0xff')などの文字列も変換できます。その際、int('10', 2)のように基数を明示的に指定します。エラーメッセージの「with base 10」は、10進数として解釈できなかったことを示しています。

Q
Linterや静的解析ツールで、このタイプのエラーを事前に検出できますか?
A

PythonのLinter(例: Pylint, Flake8)や静的解析ツール(例: MyPy)は、コードの型ヒントが正しく利用されていれば、型不一致の可能性を警告してくれることがあります。しかし、実行時にしか判明しないユーザー入力値の不正までは検出できません。ランタイムエラーは依然としてtry-exceptでのハンドリングが必要です。

この用語と一緒に知っておきたい用語

用語 この記事との関連
デバッガ エラー発生時の変数の値やプログラムの流れを確認するために使用します。
DRY原則 数値変換のバリデーションロジックを共通化することで、コードの重複を防ぎます。
try-catch Pythonではtry-exceptとして、エラー発生時のプログラム停止を防ぐための例外処理です。
アルゴリズム 入力値の検証やデータ処理のロジック構築に関連します。
定数 数値変換で使う基数(base 10など)を定数として定義する場合があるため、関連性が高いです。
免責事項: 当記事の情報は執筆時点の内容に基づいています。最新情報は各公式サイトをご確認ください。当サイトは情報提供を目的としており、資格取得・技術的対応の結果について一切の責任を負いません。

コメント