except: だけで書くと本当のバグまで隠れる
except:とだけ書くとあらゆる例外を捕まえてしまい、想定していたエラーだけでなく、コードの本当のバグ(NameErrorなど)まで静かに隠してしまいます。
なぜエラーが出ないのか
出力: 0
(エラーなし)- Pythonは何も報告しません。文法として正しいためです
出力: 0- 実際の挙動 — 期待した結果と食い違っている箇所
見つけ方- エラーが出ないので、出力を目で確かめるしかありません。この種の誤りが最も発見が遅れます
このエラーが出る典型パターン
パターン1
1 def average(nums): 2 try: 3 return total / len(nums) ^ 4 except: 5 return 0 6 7 print(average([1, 2, 3]))
totalという変数はどこにも定義されていません。本来ならNameErrorになるはずですが、exceptが何もかも捕まえてしまうため、バグに気づかないまま0が返り続けます。
直し方: total を sum(nums) にします。
パターン2
1 def total_price(items): 2 try: 3 return sum(prices) ^ 4 except: 5 return 0 6 7 print(total_price([10, 20, 30]))
pricesという変数は存在しません。bareなexceptがNameErrorまで飲み込んでしまい、合計が常に0になるバグが表に出てきません。
直し方: prices を items にします。
パターン3
1 def max_score(scores): 2 try: 3 return max(score ) ^ 4 except: 5 return 0 6 7 print(max_score([70, 85, 60]))
引数名のscoresを単数形のscoreと打ち間違えています。except:が全ての例外を握りつぶすため、この単純な誤字にすら気づけません。
直し方: score を scores にします。
パターン4
1 def get_first(items): 2 try: 3 return item [0] ^ 4 except: 5 return None 6 7 print(get_first([1, 2, 3]))
引数名itemsをitemと打ち間違えています。bareなexceptがNameErrorまで飲み込むため、Noneが返り続けても原因に気づけません。
直し方: item を items にします。
パターン5
1 def divide(a, b): 2 try: 3 return a / c ^ 4 except: 5 return -1 6 7 print(divide(10, 2))
引数名bをcと打ち間違えると、本来はNameErrorになるはずが、bareなexceptに握りつぶされて-1が返り続けます。
直し方: c を b にします。
よくある誤解
「とりあえずexceptで囲んでおけば安全」と思われがちですが、逆です。何が起きたかを特定できなくなり、デバッグを著しく困難にします。捕まえたい例外の種類は必ず明示します。
実務での勘所
bare exceptが特に危険なのは、通常の例外(Exceptionを継承するもの)だけでなく、Ctrl+Cによる中断(KeyboardInterrupt)やsys.exit()によるプログラム終了(SystemExit)まで捕まえてしまうことです。これらはExceptionではなくその親のBaseExceptionを継承しているため、except Exception:と書けば区別されますが、except:だけだと全てひとまとめに捕まります。結果として、Ctrl+Cで止めようとしても反応しないプログラムができあがることがあり、これがbare exceptが強く非推奨とされる具体的な理由です。