LaTeX962153 views
英語613639 views
数学講師2886227 views
いろは3010814 views
MathPython497343 views
高校倫理1440106 views
世界の国564520 views
小学社会310485 views
中学理科1630641 views
高校日本史190571 views
Help
Tools
NewsSpreadsheetCalendarBookkeepingSlidesTier ListPen ToolIllustrationCrayonWatercolorPixel ArtASCII ArtPerspectiveEndless StairsGraphMind MapER DiagramFamily TreeMemeCurved TextImage EditorMosaicRetro FilterPencil SketchSwirl EffectOCR/HighlighterMakeup EditorFaviconVideo TrimmerScrolling VideoVideo TitleColor PickerColor ExtractorBonfireFireworksWater RippleWater SplashBreaking GlassWood GrainMarble TextureCSS ButtonIcon MakerBar ChartGrouped Bar ChartStacked Bar ChartPie ChartLine ChartArea ChartStacked Area ChartScatter Plot3D Bar Chart3D Pie ChartBar Chart RaceBubble ChartPopulation PyramidPictogramEarningsCandlestick ChartInvestment RiskMortgage SimulatorCalculatorMatrix CalculatorFunction GraphPolynomial ExpansionVenn DiagramField VisualizerRubik's Cube Group TheoryTraveling SalesmanVoronoi and DelaunayFractalColumn ArithmeticDraw Math FiguresArithmetic AnimationArithmetic Word ProblemsCounting with Tree DiagramsCube NetsRolling DiceCross SectionsMotion PathMechanicsWavesElectromagnetic WavesLight and LensesThermodynamicsHow Semiconductors WorkMolecular StructuresAtomic OrbitalsElectrochemical CellsChemical EquilibriumCrystal LatticesBuffer pHPeriodic TableComplex IonsDNA Double HelixCell DivisionMembrane ChannelsNerve ImpulseMuscle ContractionHormones and HomeostasisRock ClassificationWeatherConstellationsSolar and Lunar Eclipses3D ModelingFloor PlanSeismic StructuresIntersection TurnMaglevCooking AnimationOrigamiLive Viewer CountGeoJSON MapRailway MapPopulation MapCrime MapLand Price MapSchool MapShrine and Castle MapHouse of Representatives MapWord MapSolitaireReversiHakoiri MusumeChessHamburgerRippleSlide Puzzle MakerNeon PinballNovel MakerJapanese Typing PracticePiano Score EditorMusic TheoryShogi StrategyPiano Rhythm Game

English

try-except を条件分岐代わりに使うパターン(Python)

Python では try-except を条件分岐の代わりに使うパターンがある。特に「許可を求めるより許しを請う方が簡単」(EAFP)の思想に基づき、まず実行してみて失敗したら対処するというスタイルだ。この記事では、try-except を条件分岐的に使う実践パターンを紹介する。

辞書アクセス:KeyError をキャッチ

辞書からキーを取得するとき、キーの存在確認を省略して例外で処理できる。

data = {"name": "Alice", "age": 30}

# 条件分岐スタイル
def get_with_if(data, key):
    if key in data:
        return data[key]
    return "デフォルト"

# try-except スタイル
def get_with_try(data, key):
    try:
        return data[key]
    except KeyError:
        return "デフォルト"

# 最もシンプル:dict.get を使う
def get_with_method(data, key):
    return data.get(key, "デフォルト")

dict.get() が最もシンプルだが、デフォルト値を動的に計算したい場合は try-except が有用だ。

def get_or_compute(cache, key, compute_func):
    try:
        return cache[key]
    except KeyError:
        value = compute_func(key)
        cache[key] = value
        return value

# 使用例
cache = {}
result = get_or_compute(cache, "x", lambda k: expensive_computation(k))

型変換:ValueError をキャッチ

ユーザー入力を数値に変換するとき、try-except パターンが自然だ。

def parse_int_with_if(s):
    # 条件分岐:事前チェックが複雑
    if s.lstrip("-").isdigit():
        return int(s)
    return None

def parse_int_with_try(s):
    # try-except:シンプル
    try:
        return int(s)
    except ValueError:
        return None

# テスト
print(parse_int_with_try("42"))     # 42
print(parse_int_with_try("-10"))    # -10
print(parse_int_with_try("3.14"))   # None
print(parse_int_with_try("hello"))  # None

float への変換も同様だ。

def parse_number(s):
    # まず int を試し、ダメなら float を試す
    try:
        return int(s)
    except ValueError:
        try:
            return float(s)
        except ValueError:
            return None

print(parse_number("42"))    # 42 (int)
print(parse_number("3.14"))  # 3.14 (float)
print(parse_number("abc"))   # None

属性アクセス:AttributeError をキャッチ

オブジェクトの属性が存在するかどうかを確認する場合。

class User:
    def __init__(self, name):
        self.name = name

class Admin(User):
    def __init__(self, name, permissions):
        super().__init__(name)
        self.permissions = permissions

def get_permissions_with_if(user):
    if hasattr(user, "permissions"):
        return user.permissions
    return []

def get_permissions_with_try(user):
    try:
        return user.permissions
    except AttributeError:
        return []

# 使用例
user = User("Alice")
admin = Admin("Bob", ["read", "write"])

print(get_permissions_with_try(user))   # []
print(get_permissions_with_try(admin))  # ["read", "write"]

インデックスアクセス:IndexError をキャッチ

リストの範囲外アクセスを安全に処理する。

def safe_get_with_if(lst, index):
    if 0 <= index < len(lst):
        return lst[index]
    return None

def safe_get_with_try(lst, index):
    try:
        return lst[index]
    except IndexError:
        return None

# 負のインデックスも考慮する場合、if は複雑になる
def safe_get_with_if_full(lst, index):
    if -len(lst) <= index < len(lst):
        return lst[index]
    return None

# try-except なら負のインデックスも自然に処理できる
items = ["a", "b", "c"]
print(safe_get_with_try(items, 10))   # None
print(safe_get_with_try(items, -1))   # "c"
print(safe_get_with_try(items, -10))  # None

ファイル操作:複数の例外をキャッチ

ファイル操作では複数の例外が発生しうるため、try-except が適している。

def read_json_config(path):
    import json
    try:
        with open(path) as f:
            return json.load(f)
    except FileNotFoundError:
        return {}  # ファイルがなければ空の設定
    except json.JSONDecodeError:
        return {}  # JSON が壊れていれば空の設定
    except PermissionError:
        raise  # 権限エラーは再送出して呼び出し側に任せる

イテレーション:StopIteration をキャッチ

イテレータから次の要素を安全に取得する。

def first_or_default(iterable, default=None):
    try:
        return next(iter(iterable))
    except StopIteration:
        return default

# 使用例
print(first_or_default([1, 2, 3]))  # 1
print(first_or_default([]))         # None
print(first_or_default([], "empty")) # "empty"

ただし、next() にはデフォルト値を指定できるため、通常はそちらを使う。

def first_or_default_simple(iterable, default=None):
    return next(iter(iterable), default)

複数の例外を一度にキャッチ

関連する複数の例外をまとめて処理できる。

def safe_divide(a, b):
    try:
        return a / b
    except (ZeroDivisionError, TypeError):
        return None

print(safe_divide(10, 2))    # 5.0
print(safe_divide(10, 0))    # None
print(safe_divide(10, "a"))  # None

else 節と finally 節の活用

try-except には elsefinally を組み合わせられる。

def process_data(data):
    try:
        result = transform(data)
    except ValueError as e:
        print(f"変換エラー: {e}")
        return None
    else:
        # 例外が発生しなかった場合のみ実行
        print("変換成功")
        return result
    finally:
        # 成功・失敗に関わらず実行
        cleanup()

else 節は、try ブロック内のコードを最小限に保ちつつ、成功時の処理を明確に分離できる。

パターン:複数の方法を順に試す

複数の変換方法を順に試すパターン。

def parse_date(s):
    from datetime import datetime
    
    formats = [
        "%Y-%m-%d",
        "%Y/%m/%d",
        "%d-%m-%Y",
        "%m/%d/%Y",
    ]
    
    for fmt in formats:
        try:
            return datetime.strptime(s, fmt)
        except ValueError:
            continue
    
    return None  # どのフォーマットにも合わなかった

print(parse_date("2024-01-15"))  # 成功
print(parse_date("01/15/2024"))  # 成功
print(parse_date("invalid"))     # None

注意点:例外を広くキャッチしすぎない

except Exception や素の except: は避けるべきだ。

# 悪い例:すべての例外をキャッチ
def bad_parse(s):
    try:
        return int(s)
    except:  # KeyboardInterrupt なども捕まえてしまう
        return None

# 悪い例:Exception は広すぎる
def still_bad_parse(s):
    try:
        return int(s)
    except Exception:  # プログラミングエラーも隠してしまう
        return None

# 良い例:具体的な例外のみキャッチ
def good_parse(s):
    try:
        return int(s)
    except ValueError:
        return None

まとめ

try-except を条件分岐代わりに使うパターンは Python では一般的だ。

適しているケース

辞書・リストアクセス、型変換、ファイル操作など、失敗の可能性がある操作。複数の例外をまとめて処理したい場合。

注意すべきこと

キャッチする例外は具体的に指定する。プログラミングエラー(TypeError、AttributeError の一部)は通常キャッチしない。パフォーマンスが重要で失敗率が高い場合は事前チェックを検討する。

try-except は Python の EAFP 文化を体現するイディオムであり、適切に使えばコードが簡潔で堅牢になる。