エラーともだち こわくないよ

Takanori Suzuki

Start Python Club logo

みんなのPython勉強会 #112 / 2025 Feb 13

今日はなすこと

  • Pythonのエラーってなに?

  • よくあるエラーのパターン

  • 例外処理

  • おまけ:better error messages

今日のゴール

  • Pythonのエラーが嫌いじゃなくなる

  • エラーと仲良くなれる

Photos 📷 Tweets 🐦 👍

#stapy / @takanory

slides.takanory.net 💻

slides.takanory.net

Who am I? / お前 誰よ 👤

takanory profile kuro-chan and kuri-chan

PyCon JP Association 🐍

日本国内のPythonユーザのために、Pythonの普及及び開発支援を行うために、継続的にカンファレンス(PyCon)を開くことを目的とした 非営利組織

www.pycon.jp

pycon jp logo

PyCon JP 2025

BeProud Inc. 🏢

  • BeProud: Pythonシステム開発、コンサル

  • connpass: IT勉強会支援プラットフォーム

  • PyQ: Python独学プラットフォーム

  • TRACERY: システム開発ドキュメントサービス

BeProud logos

BeProudメンバー募集中 kamon

Pythno求人のQRコード カジュアル面談のQRコード

Pythonのエラーってなにhate-nya

エラー好きな人? ok

エラー嫌いな人? ng

Pythonには2種類のエラー

構文エラー(syntax error)

  • Pythonの構文として正しくない

  • 構文解析時にエラーが発生

>>> for i in range(10)
  File "<python-input-1>", line 1
    for i in range(10)
                      ^
SyntaxError: expected ':'

例外(exception)

  • 構文は正しい

  • 実行時にエラーが発生

>>> 1 / 0
Traceback (most recent call last):
  File "<python-input-0>", line 1, in <module>
    1 / 0
    ~~^~~
ZeroDivisionError: division by zero

エラーが怖い?

エラーは怒っていない

  • ここが問題だよと教えてくれている

  • 問題を修正するための案内役

エラーは怒っていない

error_example.py
for i in range(10)
    print(i)
% python3.13 error_example.py 
  File ".../error_example.py", line 1  # このファイルの1行目の
    for i in range(10)
                      ^  # この場所で
SyntaxError: expected ':'  # 構文エラーが発生:`:`がここに必要

エラーの意味がわからない

Googleで検索 miru

Googleで検索

AIに質問 mita

ChatGPTで質問

長いエラーが出たらうわってなる? guruguru

大事なのは一番最後

>>> from urllib import request
>>> request.urlopen("https://httpbin.org/status/403")
Traceback (most recent call last):
  File "<python-input-1>", line 1, in <module>
    request.urlopen("https://httpbin.org/status/403")
    ~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File ".../urllib/request.py", line 189, in urlopen
    return opener.open(url, data, timeout)
           ~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^
  File ".../urllib/request.py", line 495, in open
    response = meth(req, response)
  File ".../urllib/request.py", line 604, in http_response
    response = self.parent.error(
        'http', request, response, code, msg, hdrs)
  File ".../urllib/request.py", line 533, in error
    return self._call_chain(*args)
           ~~~~~~~~~~~~~~~~^^^^^^^
  File ".../urllib/request.py", line 466, in _call_chain
    result = func(*args)
  File ".../urllib/request.py", line 613, in http_error_default
    raise HTTPError(req.full_url, code, msg, hdrs, fp)
urllib.error.HTTPError: HTTP Error 403: Forbidden

そのうち自分エラーに対処できる benkyou (ようになるはず)

よくあるエラーのパターン naruhodo

書籍からエラーの例を引用【AD】

改訂新版 最短距離でゼロからしっかり学ぶ Python入門 必修編

書籍からエラーの例を引用【AD】

どんなエラーが出る?(p18)

message.py
message = "こんにちは、Start Python Clubのみなさん!"
print(mesage)

どんなエラーが出る?(p18)

Traceback (most recent call last):
  File ".../message.py", line 2, in <module>
    print(mesage)
          ^^^^^^
NameError: name 'mesage' is not defined. \
    Did you mean: 'message'?
  • NameError:名前が見つからないエラー

  • 'mesage'という名前は定義されていません

  • 'message' と間違えてませんか?

どんなエラーが出る?(p18)

  • 変数名を修正して解決

message = "こんにちは、Start Python Clubのみなさん!"
# print(mesage)
print(message)

どんなエラーが出る?(p27)

message2.py
message = 'Start Python Club's member'
print(message)

どんなエラーが出る?(p27)

  File ".../message2.py", line 1
    message = 'One of Python's strengths is its diverse community.'
                                                                  ^
SyntaxError: unterminated string literal (detected at line 1)
  • SyntaxError:構文エラー

  • 文字列リテラルが終了していません

どんなエラーが出る?(p27)

  • クォーテーションを変更して解決

message = "Start Python Club's member"
print(message)

どんなエラーが出る?(p52)

beers.py
beers = ['Pilsner', 'Pale Ale', 'IPA']
print(beers[3])

どんなエラーが出る?(p52)

  File ".../beers.py", line 2, in <module>
    print(beers[3])
          ~~~~~^^^
IndexError: list index out of range
  • IndexError:インデックスエラー

  • インデックスが範囲外です

どんなエラーが出る?(p52)

  • 正しい範囲を指定して解決

beers = ['Pilsner', 'Pale Ale', 'IPA']
print(beers[2])

どんなエラーが出る?(p60)

beers2.py
beers = ['Pilsner', 'Pale Ale', 'IPA']
for beer in beers:
print(beer)

どんなエラーが出る?(p60)

  File ".../beers2.py", line 3
    print(beer)
    ^^^^^
IndentationError: expected an indented block after \
    'for' statement on line 2
  • IndentationError:正しくないインデントのエラー

  • 2行目のfor文のあとにインデントが必要

どんなエラーが出る?(p60)

  • インデントを追加して解決

beers = ['Pilsner', 'Pale Ale', 'IPA']
for beer in beers:
    print(beer)

どんなエラーが出る?(p61)

beers3.py
beers = ['Pilsner', 'Pale Ale', 'IPA']
for beer in beers
    print(beer)

どんなエラーが出る?(p61)

  File ".../beers3.py", line 2
    for beer in beers
                     ^
SyntaxError: expected ':'

どんなエラーが出る?(p61)

  • 末尾に:を追加して解決

beers = ['Pilsner', 'Pale Ale', 'IPA']
for beer in beers:
    print(beer)

どんなエラーが出る?(p76)

sizes.py
sizes = ("US Pint", "Half Pint")
sizes[0] = "UK Pint"

どんなエラーが出る?(p76)

Traceback (most recent call last):
  File ".../sizes.py", line 2, in <module>
    sizes[0] = "UK Pint"
    ~~~~~^^^
TypeError: 'tuple' object does not support item assignment
  • TypeError:データ型に関するエラー

  • タプルは要素の代入に対応していません

どんなエラーが出る?(p76)

  • タプル全体を上書きは可能

sizes = ("US Pint", "Half Pint")
# サイズを変更
sizes = ("UK Pint", "Half Pint")

どんなエラーが出る?(p113)

beer_dict.py
beer = {"name": "Punk IPA", "brewery": "Brewdog"}
print(beer["style"])

どんなエラーが出る?(p113)

Traceback (most recent call last):
  File ".../beer_dict.py", line 2, in <module>
    beer["style"]
    ~~~~^^^^^^^^^
KeyError: 'style'
  • KeyError:辞書のキーが存在しないエラー

どんなエラーが出る?(p113)

  • get()メソッドを使用する

beer = {"name": "Punk IPA", "brewery": "Brewdog"}
print(beer.get("style", "スタイルは不明です"))

どんなエラーが出る?(p134)

age.py
age = input("何歳ですか?")
if age >= 20:
    print("お酒が飲める年齢です")
else:
    print("お酒は飲めません")
% python3.13 age.py
何歳ですか?21

どんなエラーが出る?(p134)

% python3.13 age.py
何歳ですか?21
Traceback (most recent call last):
  File ".../age.py", line 2, in <module>
    if age >= 20:
       ^^^^^^^^^
TypeError: '>=' not supported between instances of \
    'str' and 'int'
  • TypeError:データ型に関するエラー

  • strとintの間で>=はサポートされていません

どんなエラーが出る?(p134)

  • int()で整数に変換する

age = input("何歳ですか?")
if int(age) >= 20:
    print("お酒が飲める年齢です")
else:
    print("お酒は飲めません")
% python3.13 age.py
何歳ですか?21
お酒が飲める年齢です

どんなエラーが出る?(p157)

beer_func.py
def describe_beer(beer_name, brewery):
    """ビールについての情報を出力する"""
    print(f"{beer_name}は{brewery}で作られています")

describe_beer()

どんなエラーが出る?(p157)

Traceback (most recent call last):
  File ".../beer_func.py", line 5, in <module>
    describe_beer()
    ~~~~~~~~~~~~~^^
TypeError: describe_beer() missing 2 required positional \
    arguments: 'beer_name' and 'brewery'
  • TypeError:データ型に関するエラー

  • 2つの位置引数beer_nameとbreweryがありません

どんなエラーが出る?(p157)

  • 引数を正しく指定する

def describe_beer(beer_name, brewery):
    """ビールについての情報を出力する"""
    print(f"{beer_name}は{brewery}で作られています")

describe_beer("よなよなエール", "ヤッホー")

何個わかりました?

エラーの一覧

さまざまな例外が発生する hiza-ni-ya-wo-ukete-simatte

例外が発生しても正しく動作させたい kochira

例外を処理する kamon

例外処理の基本

  • 数値以外を指定するとValueErrorが発生

age = input("何歳ですか?")
if int(age) >= 20:
    print("お酒が飲める年齢です")
else:
    print("お酒は飲めません")
% python3.13 age.py
何歳ですか?二十歳
Traceback (most recent call last):
  File "...//age.py", line 2, in <module>
    if int(age) >= 20:
       ~~~^^^^^
ValueError: invalid literal for int() with base 10: '二十歳'

例外処理の基本

  • tryexcept で例外処理

% python3.13 age2.py
何歳ですか?二十歳
数値を入力してください
age = input("何歳ですか?")
try:
    if int(age) >= 20:
        print("お酒が飲める年齢です")
    else:
        print("お酒は飲めません")
except ValueError:
    print("数値を入力してください")

例外処理の基本

  • 例外がなければ except 節は実行されない

% python3.13 age2.py
何歳ですか?21
お酒が飲める年齢です
age = input("何歳ですか?")
try:
    if int(age) >= 20:
        print("お酒が飲める年齢です")
    else:
        print("お酒は飲めません")
except ValueError:
    print("数値を入力してください")

複数の例外に対応する

  • 1つの処理で異なる種類の例外が発生する場合がある

  • ファイルからテキストを読み込む場合

  • どんな例外が考えられますか?

from pathlib import Path

p = Path("beer.txt")
text = p.read_text(encoding="utf-8")  # ここで例外発生

複数の例外に対応する

  • 例外の種類によってメッセージを出し分け

from pathlib import Path

p = Path("beer.txt")
try:
    text = p.read_text(encoding="utf-8")
except FileNotFoundError:
    print("ファイルが存在しません")
except PermissionError:
    print("ファイルの読み込み権限がありません")
except UnicodeDecodeError:
    print("utf-8のテキストじゃありません")

事前チェックと例外処理

  • 事前にチェックして例外を防げる場合もある

  • どちらを使うかはお好みで

from pathlib import Path

p = Path("beer.txt")
if not p.exists():  # ファイルの存在チェック
    print("ファイルが存在しません")
else:
    ...
	
if key in beer_dict:  # キーの存在チェック
    beer_dict[key]
else:
    ...

辞書のgetは適切に使おう

  • キー名をtypoしているのに気づかないことも

  • []なら例外で気づける

  • 型ヒントでTypedDictを使うのもあり

style = beer.get("stlye")  # typoに気づかない

class Beer(TypedDict):
    name: str
    style: str

beer: Beer = {"name": "Stone IPA", "style": "IPA"}

例外を握りつぶさない

  • 例外を隠蔽するとエラーの原因がわからなくなる

from pathlib import Path

p = Path("beer.txt")
try:
    text = p.read_text(encoding="utf-8")  # ここで例外発生
except Exception:
    pass  # なにが問題かわからなくなる

try節は短く書く

  • エラー発生時に問題を切り分けられない

from pathlib import Path

p = Path("beer.txt")
try:
    text = p.read_text(encoding="utf-8")  # ファイル読み込みエラー
    for line in text.splitlines():
        name, price_text = line.split(",")  # 分割エラー
        price = int(price_text)  # 変換エラー
        # なにか他の処理
        ...
except Exception:
    print("エラーが発生しました")

try節は短く書く

  • tryの範囲を短く

from pathlib import Path

p = Path("beer.txt")
try:
    text = p.read_text(encoding="utf-8")  # ファイル読み込みエラー
except Exception:
    print("ファイルの読み込みに失敗しました")
else:
    for line in text.splitlines():
        try:
            name, price_text = line.split(",")  # 分割エラー
            price = int(price_text)  # 変換エラー
        except ValueError as e:
            print(f"データ変換エラーが発生: {e}")
        # なにか他の処理
        ...

try節は短く書く

  • {e}で例外を見分ける

    for line in text.splitlines():
        try:
            name, price_text = line.split(",")  # 分割エラー
            price = int(price_text)  # 変換エラー
        except ValueError as e:
            print(f"データ変換エラーが発生: {e}")
# "aaaa" などカンマがない場合
データ変換エラーが発生: not enough values to unpack (expected 2, got 1)
# "aaaa,bbbb" など2番目の要素が数字じゃない
データ変換エラーが発生: invalid literal for int() with base 10: 'b'

適切な例外処理をしよう! nageta

おまけ:better error messages wao

better error messagesとは

閉じカッコ忘れ

beers = ["Punk IPA", "よなよなエール",
beer = beers[0]
  • Python 3.9だとエラーが意味不明 yabai

% Python 3.9 unclosed.py
  File ".../unclosed.py", line 2
    beer = beers[0]
         ^
SyntaxError: invalid syntax

閉じカッコ忘れ

beers = ["Punk IPA", "よなよなエール",
beer = beers[0]
  • Python 3.10だとわかりやすいmedetai

% Python 3.10 unclosed.py
  File ".../unclosed.py", line 1
    beers = ["Punk IPA", "よなよなエール",
            ^
SyntaxError: '[' was never closed

末尾の: 忘れ

beers = ['Pilsner', 'Pale Ale', 'IPA']
for beer in beers
    print(beer)
% python3.9 beers3.py
  File ".../beers3.py", line 2
    for beer in beers
                     ^
SyntaxError: invalid syntax  # 無効なシンタックス
% python3.10 beers3.py
  File ".../beers3.py", line 2
    for beer in beers
                     ^
SyntaxError: expected ':'  # ':'を忘れてません?

インデント忘れ

beers = ['Pilsner', 'Pale Ale', 'IPA']
for beer in beers:
print(beer)
% python3.9 beers2.py
  File ".../beers2.py", line 3
    print(beer)
    ^
IndentationError: expected an indented block
% python3.10 beers2.py
  File ".../beers2.py", line 3
    print(beer)
    ^
IndentationError: expected an indented block after 'for' statement on line 2

NameErrorDid you mean

message = "こんにちは、Start Python Clubのみなさん!"
print(mesage)
% python3.9 message.py
  File ".../message.py", line 3
    print(mesage)
NameError: name 'mesage' is not defined
% python3.10 message.py
  File ".../message.py", line 3
    print(mesage)
NameError: name 'mesage' is not defined. \
    Did you mean: 'message'?

Python 3.11での改善

>>> x, y, z = 1, 1, 0
>>> x / y / z
Traceback (most recent call last):
  File "<python-input-1>", line 1, in <module>
    x / y / z
    ~~~~~~^~~
ZeroDivisionError: float division by zero

Python 3.12での改善

>>> random.randint()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'random' is not defined. \
    Did you forget to import 'random'?
>>> from datetime import datatime
Traceback (most recent call last):
  File "<python-input-6>", line 1, in <module>
    from datetime import data
ImportError: cannot import name 'data' from 'datetime' (...). \
    Did you mean: 'date'?

Python 3.13での改善

>>> f = open("beer.txt", encodeng="utf-8")
Traceback (most recent call last):
  File "<python-input-7>", line 1, in <module>
    f = open("beer.txt", encodeng="utf-8")
TypeError: open() got an unexpected keyword argument 'encodeng'. \
    Did you mean 'encoding'?

エラーメッセージが改善されている
新しいバージョンを使おう isogu

まとめ good

  • エラーが出たら調べる

    • そのうち読めるようになる

  • よくあるエラーを紹介

    • NameErrorSyntaxErrorIndexErrorIndentationErrorTypeErrorKeyError

  • 例外処理の基本と気をつけるポイント

エラーとともだちになれそう? nakayoshi

お知らせ

Thank You pray

slides.takanory.net

takanory takanory takanory takanory

takanory profile kuro-chan and kuri-chan