Pythonを学び始めると、ちょっとしたミスでエラーが頻発しますが、その多くは原因とパターンが決まっています。
本記事では、初心者が最初に出会いやすい5大エラ
この5つを取り上げ、具体的な原因と実践的な対策を、短いサンプルコードとともに丁寧に解説します。
エラーの正体を知れば、怖さはぐっと減ります。
Pythonの見つからない系エラー(NameError/AttributeError)
NameErrorの原因(未定義名・スペルミス)
NameErrorは、名前
(変数名、関数名、定数名など)が見つからない時に起きます。
典型的には、定義より先に使ってしまう、もしくはスペルミスです。
さらに、関数内でのスコープの扱いを誤ってUnboundLocalError(NameErrorの一種)が出ることもあります。
例1: 定義より先に参照してしまう
# 円の面積を計算するつもりが、定数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
# スペルミスの例
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の対策(宣言順とスコープを確認)
使う前に定義する、そしてスコープ(どこで有効な名前か)を意識することが決定打です。
関数に必要な値は引数で受け取り、グローバル変数に依存しない設計にすると安全です。
# 事前定義と引数での受け渡しで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
どうしてもグローバル変数を更新したい場合はglobal
やnonlocal
を使えますが、初心者のうちは関数引数で渡す設計の方がシンプルで安全です。
AttributeErrorの原因(存在しない属性やメソッド)
AttributeErrorは、obj.attr
やobj.method()
のようにアクセスした属性やメソッドが存在しない時に起きます。
主な原因は以下です。
- オブジェクトの型が想定と異なる(intに
.lower()
など) - NoneTypeにアクセスしている(関数がNoneを返したのに気付かず
.group()
などを呼ぶ) - dictのキーを
.
で読もうとしている(ドットではなく[]
が必要)
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
で分岐します。
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は、演算
や関数呼び出し
の形が対応する型と合っていない時に出ます。
よくあるのは、数値と文字列の足し算、呼び出し不可の値を関数のように実行、引数の数違いなどです。
# 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)
で判定できます。
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の対策(関数の引数と戻り値を確認)
関数の定義と呼び出しが一致しているかを確認します。
引数の数、位置、型、戻り値の型を意識するとエラーが減ります。
型ヒントを添えると読み間違いが減ります。
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です。
設定ミスや外部データの欠損で発生しがちです。
user = {"name": "taro"}
print(user["age"]) # KeyError: 'age' (キーが存在しない)
Traceback (most recent call last):
...
KeyError: 'age'
KeyErrorの対策(inとgetで存在確認)
存在確認を習慣化しましょう。
読み取りではin
やget()
、更新ではsetdefault()
やdict.setdefault
が便利です。
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()
や、オフバイワン(最後の位置を超えてアクセス)でよく起きます。
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()
を使います。
スライスは範囲外でもエラーになりません。
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の補完を活用しましょう。
似た名前を乱立させず、短くても意味が伝わる名前に統一します。
# 悪い例: スペルが揺れている
usr_name = "taro"
usernmae = "taro"
user_name = "taro"
# 良い例: 統一
user_name = "taro"
Noneの可能性を先に潰す(isやifでチェック)
‘NoneType’ object has no attribute …は非常に多いです。
戻り値がNoneになり得る関数では、使う前にis None
で早めに分岐します。
def find_user(id_):
# 見つからなければNoneを返す想定
return None
u = find_user(123)
if u is None:
print("ユーザーが見つかりません")
else:
print(u["name"]) # Noneでないことが保証される
ユーザーが見つかりません
存在確認と境界チェックを習慣化する
辞書キーはin
やget
、リストはlen
やenumerate
でガードします。
「アクセス前に確かめる」をルール化すると、KeyError/IndexErrorの大半は防げます。
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
が安全です。
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つです。
エラーは避けるものではなく、正しく読み解いて素早く対処する対象です。
最後に早見表を置きますので、実装中のチェックリスト代わりに活用してください。
エラー早見表
エラー種別 | 典型メッセージ例 | 代表的な原因 | 主な対策 |
---|---|---|---|
NameError | name ‘x’ is not defined | 宣言前の参照、スペルミス、スコープ誤り | 先に定義、スペル統一、引数で受け渡し |
AttributeError | ‘NoneType’ object has no attribute ‘x’ | Noneに対する属性アクセス、型の取り違え | type/hasattr確認、Noneチェック、getattr |
TypeError | unsupported operand type(s) | 型不一致、非呼び出しオブジェクト呼び出し、引数数違い | 明示的な型変換、callable確認、定義と呼び出しの整合 |
KeyError | ‘key’ | 辞書にキーが存在しない | inやgetで確認、setdefaultやdefault値 |
IndexError | list index out of range | 範囲外アクセス、空リストからpop | lenで境界チェック、スライス、enumerate |
エラーのメッセージは最良のナビゲーターです。
行番号と内容を丁寧に読み、原因をパターン化していくと、デバッグ速度は急速に上がります。
今日の対策を日々の習慣に落とし込み、快適なPythonライフを手に入れてください。