ガイド

pythonスクリプトが落ちる原因はUnboundLocalError、run_owner_todo.py list調査記録

2026-11-02

この記事で切り分けられること

python のスクリプトが毎回同じ箇所で UnboundLocalError を出して落ちる場合に、どこを見れば原因が分かるかをまとめる。特に「代入しているはずの変数なのに未代入エラーになる」ケースを扱う。対象は 2026-11-01 にクラウド側で見つかった run_owner_todo.py の list コマンドが落ちる不具合。

症状

以下のコマンドを実行すると、毎回同じエラーで落ちる。

py -3 scripts/run_owner_todo.py list
UnboundLocalError: cannot access local variable 'rows'

台帳側にはデータがあるのに、コマンドで一覧を見ようとすると1件も表示されない。コックピットの「今日」②にあたる本人作業一覧が、コマンド経由では常に空扱いになっていた。

原因

main() の中に list 分岐と done 分岐があり、done 分岐で次のようなコードになっていた。

def main():
    args = parse_args()

    if args.command == "list":
        for r in rows():
            print(r)

    if args.command == "done":
        rows = requests.get("<あなたのAPIのURL>").json()
        mark_done(rows, args.id)

ここでのポイントは、rows という名前がモジュール関数 rows() と同じ名前で、done 分岐の中でローカル変数として代入されていたこと。

Python はコンパイル時に関数全体を見て、その関数内のどこかに代入文があれば、その名前を 関数全体のローカル変数として扱う。これは実行時にどの分岐を通るかとは関係ない。つまり、done 分岐にしか出てこない rows = ... という代入があるだけで、main() 関数全体において rows はローカル変数扱いになる。

その結果、list 分岐の for r in rows(): は、モジュール関数の rows() を呼んでいるつもりでも、Python 側は「まだ代入されていないローカル変数 rows を読もうとしている」と解釈し、UnboundLocalError になる。list コマンドを選んでも done 分岐を一度も実行しなくても、このエラーは起きる。

直し方

done 分岐のローカル変数名を、モジュール関数 rows() と被らない名前に変更する。

def main():
    args = parse_args()

    if args.command == "list":
        for r in rows():
            print(r)

    if args.command == "done":
        open_rows = requests.get("<あなたのAPIのURL>").json()
        mark_done(open_rows, args.id)

この変更だけで、list 分岐はモジュール関数 rows() を正しく呼べるようになり、エラーが消えた。

py -3 scripts/run_owner_todo.py list

台帳にある本人作業の一覧が、コマンドでも表示されるようになった。

再発防止

それでも駄目なときに次に見る場所

  1. エラーメッセージに出てくる変数名で、同じ関数内を grep し、代入文(= の左辺)がないか確認する。
  2. その変数名がモジュール関数やモジュール変数と同じ名前になっていないか確認する。
  3. 分岐が複数ある関数では、各分岐でどの名前に代入しているかを一覧にして、重複がないか突き合わせる。
  4. 修正後は、エラーが出ていた分岐だけでなく、他の分岐も実際に実行して結果を確認する。

同じような作業を自動にできるかどうか、無料でお返しします。いまのファイルと手順を見せてください。

お問い合わせ →