Fix AttributeError: 'NoneType' object has no attribute in Python

beginner🐍 Python2026-03-17| Python 2.7 / Python 3.x(Linux、macOS、Windows)

Error Message

AttributeError: 'NoneType' object has no attribute 'split'
#python#attributeerror#nonetype#debugging

エラーの内容

Pythonスクリプトが次のようなエラーでクラッシュします:

AttributeError: 'NoneType' object has no attribute 'split'

has no attribute の後に続くメソッド名は状況によって異なります — 'lower''strip''replace'、あるいは他の文字列メソッドの場合もあります。しかし原因は常に同じです:コードのどこかで、変数が期待していた文字列(またはリスト、オブジェクト)ではなく None を保持しています。

根本原因

Pythonにおける None は独自の特殊な型 NoneType です。文字列メソッドもリストメソッドも、何も持っていません。.split() を呼び出すと、Pythonは何が問題だったかを正確に教えてくれます。

ほぼ10回中9回は、次のいずれかが原因です:

  • return 文が抜けているために関数が暗黙的に None を返している
  • 変数が一度も代入されていない、または明示的に None に設定されている
  • 正規表現のマッチや辞書の検索で何も見つからず None が返された
  • APIレスポンスやファイル読み込みの結果が空だった

クイック診断

まず、どの変数None なのかを特定します。クラッシュしている行の直前に print() を追加してみましょう:

# クラッシュしている行:
result = user_input.split(",")

# この行をその上に追加する:
print(type(user_input), repr(user_input))

出力に <class 'NoneType'> None が表示されたら、それが問題の変数です。その変数がその値を持つようになった経緯をコードで遡りましょう — 修正はほぼ必ず一つ前のステップにあります。

修正1 — 値を提供している関数を確認する

return 文の書き忘れが最大の原因です。条件に当たったものの何も返すのを忘れた関数は、こっそり None を返します。

# 問題あり — 暗黙的にNoneを返す
def get_username(data):
    if data:
        username = data["name"]
        # returnを忘れている!

name = get_username({"name": "alice"})
parts = name.split(" ")  # AttributeError

# 修正済み
def get_username(data):
    if data:
        return data["name"]
    return ""  # または例外を発生させる

name = get_username({"name": "alice"})
parts = name.split(" ")  # 正常動作: ['alice']

関数のすべての分岐を確認してください。return なしで終了できる分岐があれば、Pythonは黙って None を補完します。

修正2 — Noneチェックでガードする

None が有効な結果となる場合もあります — オプションフィールド、欠落した設定キー、「見つからない」レスポンスなどです。メソッドを呼び出す前にガード処理を入れましょう:

value = some_function()

# 方法A:明示的なチェック
if value is not None:
    parts = value.split(",")
else:
    parts = []

# 方法B:ワンライナーのフォールバック
parts = (value or "").split(",")

方法Bは簡潔です。ただし注意が必要です — or ""None だけでなく、空文字列や 0 でも発動します。その区別が重要な場合は value is not None を使いましょう。

修正3 — 辞書と正規表現の検索を修正する

何も見つからないときに暗黙的に None を返すPython組み込みが2つあります:dict.get()re.search() です。

# 辞書 — デフォルト値を使う
data = {"city": "Hanoi"}
country = data.get("country")     # Noneを返す
parts = country.split("-")         # AttributeError

# 修正:フォールバックを指定する
country = data.get("country", "")  # NoneではなくStringを返す
parts = country.split("-")         # 正常動作: ['']

import re

text = "hello world"
match = re.search(r"(\d+)", text)   # 数字なし — Noneを返す
result = match.group(1)              # AttributeError

# 修正:使用前にチェックする
if match:
    result = match.group(1)
else:
    result = None

修正4 — 外部ソースからのNoneを処理する

HTTP API、データベース、ファイル読み込みにはすべて共通点があります:何も返さないことがあるのです。JSONレスポンスにフィールドが存在しない場合もあります。データベースの行が存在しない場合もあります。外部データが常にクリーンだと思い込まないようにしましょう。

import requests

response = requests.get("https://api.example.com/user/1")
data = response.json()

# リスクあり
name = data.get("name")
first, last = name.split(" ")   # nameがNoneの場合はAttributeError

# 安全
name = data.get("name") or ""
if " " in name:
    first, last = name.split(" ", 1)
else:
    first, last = name, ""

修正5 — 型アノテーションと早期バリデーションを使う

大規模なプロジェクトでは、None が3〜4回の関数呼び出しを経た後、ロジックの深い場所でクラッシュすることがあります。これはデバッグが非常に困難です。解決策はエントリポイントでバリデーションを行うことです。

def process_input(text: str) -> list[str]:
    if not isinstance(text, str):
        raise TypeError(f"str型を期待しましたが、{type(text).__name__}型が渡されました")
    return text.split(",")

# これにより、後から混乱するAttributeErrorではなく、すぐに明確なTypeErrorが発生する
process_input(None)

2行目で発生する明確な TypeError: str型を期待しましたが、NoneType型が渡されました は、別モジュールの87行目に埋もれた AttributeError よりはるかに分かりやすいです。

修正の確認

PythonのREPLまたはテストスクリプトで簡単に動作確認します:

value = None
result = (value or "").split(",")
print(result)   # 期待値: ['']

value = "a,b,c"
result = (value or "").split(",")
print(result)   # 期待値: ['a', 'b', 'c']

どちらもエラーなく実行されるはずです。pytest を使っている場合は、None ケースの明示的なテストを追加しましょう:

def test_handles_none_input():
    assert process_csv(None) == []
    assert process_csv("a,b") == ["a", "b"]

予防チェックリスト

  • 値を返す関数はすべての分岐で明示的な return が必要です — 例外なし
  • キーが存在しない可能性がある場合は dict[key] の代わりに dict.get(key, default) を使う
  • re.search() / re.match() の結果は .group() を呼ぶ前に必ず確認する
  • 外部データ(API、DB、ユーザー入力)はロジックの深部ではなく、エントリポイントでバリデーションを行う
  • mypy または pyright を実行する — コードが実行される前に Optional[str] の誤用を検出してくれる

Related Error Notes