閉じる

Pythonのよくある5大エラーの原因と対策

Pythonを学び始めると、ちょっとしたミスでエラーが頻発しますが、その多くは原因とパターンが決まっています。

本記事では、初心者が最初に出会いやすい5大エラ

この5つを取り上げ、具体的な原因と実践的な対策を、短いサンプルコードとともに丁寧に解説します。

エラーの正体を知れば、怖さはぐっと減ります

Pythonの見つからない系エラー(NameError/AttributeError)

NameErrorの原因(未定義名・スペルミス)

NameErrorは、名前(変数名、関数名、定数名など)が見つからない時に起きます。

典型的には、定義より先に使ってしまう、もしくはスペルミスです。

さらに、関数内でのスコープの扱いを誤ってUnboundLocalError(NameErrorの一種)が出ることもあります。

例1: 定義より先に参照してしまう

Python
# 円の面積を計算するつもりが、定数PIを定義する前に使ってしまう例
def area_of_circle(r):
    return r * r * PI  # ここでNameError: 'PI' is not defined

print(area_of_circle(2))

PI = 3.14  # 後から定義しても遅い
実行結果
Traceback (most recent call last):
  File "example.py", line 5, in <module>
    print(area_of_circle(2))
  File "example.py", line 3, in area_of_circle
    return r * r * PI
NameError: name 'PI' is not defined

例2: スペルミスとUnboundLocalError

Python
# スペルミスの例
usernme = "taro"
print(username)  # NameError: 'username' は未定義 (綴りが違う)

# スコープの例(関数内で代入があるとローカル変数とみなされる)
x = 10

def inc():
    # 下の行で代入があるため、xはローカル扱いになる
    # しかし代入前に参照してしまい、UnboundLocalErrorになる
    x += 1
    return x

print(inc())
実行結果
Traceback (most recent call last):
  ...
NameError: name 'username' is not defined

Traceback (most recent call last):
  ...
UnboundLocalError: cannot access local variable 'x' where it is not associated with a value

NameErrorの対策(宣言順とスコープを確認)

使う前に定義する、そしてスコープ(どこで有効な名前か)を意識することが決定打です。

関数に必要な値は引数で受け取り、グローバル変数に依存しない設計にすると安全です。

Python
# 事前定義と引数での受け渡しでNameErrorを回避
PI = 3.14  # 使う前に定義

def area_of_circle(r, pi=PI):  # デフォルト引数で外部定数も受け取れる
    return r * r * pi

def inc(value):  # グローバルxに依存せず、値を受け取って返す
    return value + 1

print(area_of_circle(2))
print(inc(10))
実行結果
12.56
11
補足

どうしてもグローバル変数を更新したい場合はglobalnonlocalを使えますが、初心者のうちは関数引数で渡す設計の方がシンプルで安全です。

AttributeErrorの原因(存在しない属性やメソッド)

AttributeErrorは、obj.attrobj.method()のようにアクセスした属性やメソッドが存在しない時に起きます。

主な原因は以下です。

  • オブジェクトの型が想定と異なる(intに.lower()など)
  • NoneTypeにアクセスしている(関数がNoneを返したのに気付かず.group()などを呼ぶ)
  • dictのキーを.で読もうとしている(ドットではなく[]が必要)
Python
import re

text = 123
print(text.lower())  # AttributeError: 'int' object has no attribute 'lower'

m = re.match(r"\d+", "abc")  # 先頭が数字でないのでマッチしない → None
print(m.group(0))            # AttributeError: 'NoneType' object has no attribute 'group'

user = {"name": "taro"}
print(user.name)  # AttributeError: 'dict' object has no attribute 'name' (キーは[]でアクセス)
実行結果
Traceback (most recent call last):
  ...
AttributeError: 'int' object has no attribute 'lower'
Traceback (most recent call last):
  ...
AttributeError: 'NoneType' object has no attribute 'group'
Traceback (most recent call last):
  ...
AttributeError: 'dict' object has no attribute 'name'

AttributeErrorの対策(オブジェクトの型と属性名を確認)

まずtype(obj)で型を確認し、目的の属性やメソッドがあるかをdir()やドキュメントで確かめるのが基本です。

Noneの可能性があると分かっている時はif obj is not Noneで分岐します。

Python
import re

text = "HELLO"
if isinstance(text, str):            # 型を確認
    print(text.lower())              # OK: strはlowerを持つ

m = re.match(r"\d+", "abc")
if m is not None:                    # Noneチェック
    print(m.group(0))
else:
    print("マッチしませんでした")

user = {"name": "taro"}
print(user.get("name"))              # dictのキーは[]またはgetでアクセス
実行結果
hello
マッチしませんでした
taro
小技

属性アクセスでデフォルトを返したい時はgetattr(obj, "attr", default)、存在を事前に確認したい時はhasattr(obj, "attr")が使えます。

Pythonの型エラー(TypeError)

TypeErrorの原因(型不一致や呼び出しミス)

TypeErrorは、演算関数呼び出しの形が対応する型と合っていない時に出ます。

よくあるのは、数値と文字列の足し算、呼び出し不可の値を関数のように実行、引数の数違いなどです。

Python
# 1) 数値と文字列の足し算
price = 1000
unit = "円"
print(price + unit)  # TypeError

# 2) 呼び出し不可オブジェクトの呼び出し
items = [1, 2, 3]
print(items(5))  # TypeError: 'list' object is not callable

# 3) 引数の数が合わない
def add(a, b):
    return a + b

print(add(1))  # TypeError: missing required positional argument 'b'
実行結果
Traceback (most recent call last):
  ...
TypeError: unsupported operand type(s) for +: 'int' and 'str'
Traceback (most recent call last):
  ...
TypeError: 'list' object is not callable
Traceback (most recent call last):
  ...
TypeError: add() missing 1 required positional argument: 'b'

TypeErrorの対策(型をそろえる/明示的に型変換)

型をそろえるのが根本対策です。

文字列化はstr()、数値化はint()/float()などを使います。

呼び出し可能かはcallable(obj)で判定できます。

Python
price = 1000
unit = "円"

# 数値と文字列の結合は、f文字列やstr()で揃える
print(f"{price}{unit}")        # "1000円"
print(str(price) + unit)       # 同じ結果

# 呼び出し可能かの確認(必要なら)
items = [1, 2, 3]
print(callable(items))         # False → 関数のようには呼び出せない
実行結果
1000円
1000円
False

TypeErrorの対策(関数の引数と戻り値を確認)

関数の定義と呼び出しが一致しているかを確認します。

引数の数、位置、型、戻り値の型を意識するとエラーが減ります。

型ヒントを添えると読み間違いが減ります。

Python
from typing import Iterable, List

def repeat_each(xs: Iterable[str], times: int) -> List[str]:
    """各要素をtimes回繰り返す"""
    return [x for x in xs for _ in range(times)]

names = ["a", "b", "c"]
print(repeat_each(names, 2))  # 引数の型・数を満たす
実行結果
['a', 'b', 'c', 'a', 'b', 'c']
注意

組み込み名(list, dict, strなど)を変数名として使うと、思わぬTypeError('list' object is not callableなど)を誘発します。

予約語や組み込み名は変数名に使わないようにしましょう。

Pythonのコレクション参照エラー(KeyError/IndexError)

KeyErrorの原因(辞書にないキー)

辞書に存在しないキーを[]で取得しようとするとKeyErrorです。

設定ミスや外部データの欠損で発生しがちです。

Python
user = {"name": "taro"}
print(user["age"])  # KeyError: 'age' (キーが存在しない)
実行結果
Traceback (most recent call last):
  ...
KeyError: 'age'

KeyErrorの対策(inとgetで存在確認)

存在確認を習慣化しましょう。

読み取りではinget()、更新ではsetdefault()dict.setdefaultが便利です。

Python
user = {"name": "taro"}

# in で存在確認してから読む
if "age" in user:
    print(user["age"])
else:
    print("ageキーはありません")

# getでデフォルト値を返す(エラーにならない)
age = user.get("age", 0)
print(f"age={age}")

# 書き込み時にデフォルト初期化したいなら setdefault
counts = {}
counts.setdefault("apple", 0)
counts["apple"] += 1
print(counts)
実行結果
ageキーはありません
age=0
{'apple': 1}

IndexErrorの原因(リストの範囲外アクセス)

リストのインデックスが範囲外の時にIndexErrorです。

空リストからのpop()や、オフバイワン(最後の位置を超えてアクセス)でよく起きます。

Python
nums = [10, 20]
print(nums[2])  # IndexError: 範囲外 (有効範囲は0,1)

stack = []
stack.pop()     # IndexError: 空からは取り出せない
実行結果
Traceback (most recent call last):
  ...
IndexError: list index out of range
Traceback (most recent call last):
  ...
IndexError: pop from empty list

IndexErrorの対策(lenで範囲チェック/安全なスライス)

アクセス前にlen()で範囲をチェックし、イテレーションはインデックスではなく要素で回すのが安全です。

必要に応じてenumerate()を使います。

スライスは範囲外でもエラーになりません。

Python
nums = [10, 20, 30]

# 1) 範囲チェック
idx = 2
if 0 <= idx < len(nums):
    print(nums[idx])
else:
    print("範囲外です")

# 2) 直接イテレーション (IndexErrorを回避)
for n in nums:
    print(n)

# 3) enumerateでインデックスと値を同時に
for i, n in enumerate(nums):
    print(i, n)

# 4) スライスは安全に先頭3件(不足分は無視)
print(nums[:5])  # [10, 20, 30]
実行結果
30
10
20
30
0 10
1 20
2 30
[10, 20, 30]

Python初心者向けの共通の予防策

変数名と属性名のスペルを統一する

スペルの揺れはNameError/AttributeErrorの温床です。

命名規則(例: スネークケース)を決め、IDEの補完を活用しましょう。

似た名前を乱立させず、短くても意味が伝わる名前に統一します。

Python
# 悪い例: スペルが揺れている
usr_name = "taro"
usernmae = "taro"
user_name = "taro"

# 良い例: 統一
user_name = "taro"

Noneの可能性を先に潰す(isやifでチェック)

‘NoneType’ object has no attribute …は非常に多いです。

戻り値がNoneになり得る関数では、使う前にis Noneで早めに分岐します。

Python
def find_user(id_):
    # 見つからなければNoneを返す想定
    return None

u = find_user(123)
if u is None:
    print("ユーザーが見つかりません")
else:
    print(u["name"])  # Noneでないことが保証される
実行結果
ユーザーが見つかりません

存在確認と境界チェックを習慣化する

辞書キーはinget、リストはlenenumerateでガードします。

「アクセス前に確かめる」をルール化すると、KeyError/IndexErrorの大半は防げます。

Python
data = {"items": ["A", "B"]}

# 安全な取り出し
if "items" in data and len(data["items"]) >= 2:
    second = data["items"][1]
    print(second)
else:
    print("必要な要素がありません")
実行結果
B

暗黙の型変換に頼らず明示的に変換する

Pythonは自動変換をあまりしません。

結合や比較の前に、意図した型へ明示的に変換しましょう。

フォーマットはf"..."formatが安全です。

Python
age = "20"        # 文字列
n = 1             # 数値

# 明示的に変換
age_num = int(age)
print(age_num + n)

# 表示はf文字列で
print(f"年齢は{age_num}歳です")
実行結果
21
年齢は20歳です

まとめ

本記事では、NameError/AttributeError/TypeError/KeyError/IndexErrorの5大エラーを、原因と具体策のセットで解説しました。

要点は「使う前に定義」「型と存在の確認」「Noneを早めに処理」「境界チェック」「明示的な型変換」の5つです。

エラーは避けるものではなく、正しく読み解いて素早く対処する対象です。

最後に早見表を置きますので、実装中のチェックリスト代わりに活用してください。

エラー早見表

エラー種別典型メッセージ例代表的な原因主な対策
NameErrorname ‘x’ is not defined宣言前の参照、スペルミス、スコープ誤り先に定義、スペル統一、引数で受け渡し
AttributeError‘NoneType’ object has no attribute ‘x’Noneに対する属性アクセス、型の取り違えtype/hasattr確認、Noneチェック、getattr
TypeErrorunsupported operand type(s)型不一致、非呼び出しオブジェクト呼び出し、引数数違い明示的な型変換、callable確認、定義と呼び出しの整合
KeyError‘key’辞書にキーが存在しないinやgetで確認、setdefaultやdefault値
IndexErrorlist index out of range範囲外アクセス、空リストからpoplenで境界チェック、スライス、enumerate

エラーのメッセージは最良のナビゲーターです。

行番号と内容を丁寧に読み、原因をパターン化していくと、デバッグ速度は急速に上がります。

今日の対策を日々の習慣に落とし込み、快適なPythonライフを手に入れてください。

この記事を書いた人
エーテリア編集部
エーテリア編集部

人気のPythonを初めて学ぶ方向けに、文法の基本から小さな自動化まで、実際に手を動かして理解できる記事を書いています。

クラウドSSLサイトシールは安心の証です。

URLをコピーしました!