Kodrill

Python の言語仕様

Python 3 エンジニア認定実践試験

例外処理・with 文・構造的パターンマッチ・関数の引数・アンパック・内包表記・ジェネレーター・デコレーター

問題数
25 問
合格ライン
70%
実行して確認済み
23 問
この分野の要点を読む7 章・約 16 分。実行して確かめたコード例と、試験でよくある引っかけをまとめています

ログインなしで試す

無料の 5 問を、1問ごとに正誤と解説を見ながら解けます。解答は保存されません。

5 問を試す

無料登録して学習を記録する

学習履歴・ダッシュボード・ブックマーク・模試モードが使えます。

★ 残り 20 問はプレミアム会員限定です

無料プランでは先頭 5 問まで解けます。プレミアムなら全問題・苦手問題の復習・広告非表示が使えます。
料金プランを見る

問題と解説を見る (無料)

登録しなくても、次の5問は問題文と解説をそのまま読めます。

Python の言語仕様の要点

内容の確認日: 2026-10-04

この分野は『Python実践レシピ』の第 3 章 (Python の言語仕様) に対応し、40 問中 7 問と、実践試験でもっとも出題の多い章です。基礎試験で学んだ文法を一歩進め、例外の連鎖・コンテキストマネージャー・ジェネレーター・デコレーターなど、ライブラリを書くときに使う仕組みが問われます。

コードを読んで「何が出力されるか」を答える問題が中心です。どの順番で実行されるか、いつ評価されるかを、実際に動かして確かめながら覚えるのが近道です。

例外処理と例外の連鎖

try 文は、try 節 → (例外があれば) 合う except 節 → (例外がなければ) else 節 → finally 節の順に実行されます。except は上から順に調べ、最初に合った 1 つだけが実行されるので、具体的な例外を先に書きます。

例外を捕捉して別の例外に置き換えるときは、raise 新しい例外 from 元の例外 と書きます。元の例外は新しい例外の __cause__ 属性に入り、トレースバックにも両方が表示されるので、原因をたどれます。

Python
class ConfigError(Exception):    pass​def load_port(text):    try:        return int(text)    except ValueError as e:        raise ConfigError(f"ポート番号が不正: {text}") from e​try:    load_port("80a")except ConfigError as e:    print(e)    print(type(e.__cause__).__name__)
ターミナル
python3 main.py
ポート番号が不正: 80a
ValueError

Python 3.11 からは、複数の例外をまとめた ExceptionGroup と、その中から型ごとに取り出して処理する except* 節も使えます。except* は、グループのうち合う例外をすべて処理し、残りを次の except* 節に回します。

Python
try:    raise ExceptionGroup("検証エラー", [ValueError("年齢"), TypeError("名前"), ValueError("住所")])except* ValueError as group:    print("値の誤り:", [str(e) for e in group.exceptions])except* TypeError as group:    print("型の誤り:", [str(e) for e in group.exceptions])
ターミナル
python3 main.py
値の誤り: ['年齢', '住所']
型の誤り: ['名前']

with 文とコンテキストマネージャー

with 文は、ブロックに入るときに __enter__、抜けるときに __exit__ を呼びます。ブロックの中で例外が起きても __exit__ は必ず呼ばれるので、ファイルを閉じる・ロックを解放するなどの後始末を確実に行えます。__enter__ の戻り値は as の変数に入ります。

__exit__ は例外の情報 (型・値・トレースバック) を受け取り、真の値を返すと例外を握りつぶします。普通は None (偽) を返し、例外をそのまま外に伝えます。

簡単なコンテキストマネージャーは、contextlib.contextmanager を付けたジェネレーター関数で書けます。yield の前が入るときの処理、後が抜けるときの処理で、yield した値が as の変数に入ります。例外が起きても後始末をするには、yield を try・finally で囲みます。

Python
from contextlib import contextmanager, suppress​@contextmanagerdef section(name):    print(f"[{name} 開始]")    try:        yield name.upper()    finally:        print(f"[{name} 終了]")​with section("load") as label:    print("処理中:", label)​with suppress(KeyError):    {}["missing"]print("KeyError は無視された")
ターミナル
python3 main.py
[load 開始]
処理中: LOAD
[load 終了]
KeyError は無視された

contextlib.suppress(例外) は、指定した例外が起きたらそれを無視してブロックを抜けるコンテキストマネージャーです。

構造的パターンマッチ (match 文)

Python 3.10 で追加された match 文は、値の「形」で分岐します。case は上から順に調べ、最初に一致したものだけを実行します。主なパターンは次のとおりです。

・リテラルパターン: case 404: のように値と比べる。case 200 | 201: のように | で「いずれか」を書ける ・取り出しパターン: case code: のように変数名だけを書くと、何にでも一致し、値がその変数に入る ・ワイルドカード: case _: は何にでも一致し、値を取り出さない (最後の「それ以外」に使う) ・シーケンスパターン: case ["go", direction]: のように要素の数と並びで照合する。*rest で残りをまとめて受け取れる ・マッピングパターン: case {"type": "user"}: は、そのキーと値を含む辞書に一致する。余分なキーがあっても一致する ・クラスパターン: case Point(x=0, y=y): は型と属性を照合する。case str(name): は str のときだけ一致する

case の後に if 条件 (ガード) を付けると、パターンが一致し、かつ条件が真のときだけその case が選ばれます。

Python
def handle(event):    match event:        case {"type": "click", "pos": (x, y)} if x < 0 or y < 0:            return "画面外のクリック"        case {"type": "click", "pos": (x, y)}:            return f"クリック ({x}, {y})"        case {"type": "key", "key": "q" | "Q"}:            return "終了"        case {"type": str(kind)}:            return f"未対応: {kind}"        case _:            return "不正なイベント"​print(handle({"type": "click", "pos": (3, 4), "time": 10}))print(handle({"type": "click", "pos": (-1, 4)}))print(handle({"type": "key", "key": "Q"}))print(handle({"type": "scroll"}))print(handle(["click"]))
ターミナル
python3 main.py
クリック (3, 4)
画面外のクリック
終了
未対応: scroll
不正なイベント

1 つ目のイベントには "time" という余分なキーがありますが、マッピングパターンは余分なキーを無視するので一致します。シーケンスパターンは文字列には一致しない (文字列を 1 文字ずつの並びとはみなさない) 点も覚えておきましょう。

関数の引数とアンパック

引数リストの / より前は位置専用引数 (キーワードで渡せない)、* より後はキーワード専用引数 (位置では渡せない) です。*args は余った位置引数をタプルに、**kwargs は余ったキーワード引数を辞書にまとめます。*args の後に書いた引数もキーワード専用になります。

Python
def request(url, /, method="GET", *, timeout=10, **headers):    return f"{method} {url} timeout={timeout} {headers}"​print(request("/a"))print(request("/b", "POST", timeout=3, accept="json"))try:    request(url="/c")except TypeError:    print("url はキーワードで渡せない")
ターミナル
python3 main.py
GET /a timeout=10 {}
POST /b timeout=3 {'accept': 'json'}
url はキーワードで渡せない

デフォルト値は関数を定義したときに 1 回だけ評価されます。リストなど変更可能なオブジェクトをデフォルト値にすると、呼び出しをまたいで同じオブジェクトが使われてしまうので、None を既定にして関数の中で作ります。

アンパックは、代入では first, *rest = 値 のように * で残りをまとめて受け取り (常にリストになる)、呼び出しでは f(*リスト, **辞書) で要素を引数に展開します。辞書は {**a, **b} や a | b で合わせられ、同じキーは後ろの値になります。

Python
head, *body, tail = "python"print(head, body, tail)​point = {"x": 1, "y": 2}print({**point, "y": 20, "z": 3})print(max(*[3, 9, 4]))
ターミナル
python3 main.py
p ['y', 't', 'h', 'o'] n
{'x': 1, 'y': 20, 'z': 3}
9

内包表記とジェネレーター

内包表記は、[式 for 変数 in 反復可能 if 条件] (リスト)・{キー: 値 for ...} (辞書)・{式 for ...} (集合) の 3 種類です。for を複数書くと、左の for が外側のループになります。

丸かっこで書く (式 for ...) はタプルではなくジェネレーター式で、値を 1 つずつ必要になったときに計算します (遅延評価)。全体をメモリに持たないので、大きなデータの合計などに向いています。

関数の中で yield を使うとジェネレーター関数になり、呼び出すとジェネレーターが返ります。next() や for で値を要求するたびに、前回の yield の続きから実行が再開します。最後まで進んだジェネレーターは空になり、もう一度は使えません。

Python
def read_lines():    for line in ["a", "", "b", "c"]:        print(f"(読み込み {line!r})")        yield line​non_empty = (line for line in read_lines() if line)print("まだ読み込んでいない")print(next(non_empty))print(list(non_empty))print(list(non_empty))
ターミナル
python3 main.py
まだ読み込んでいない
(読み込み 'a')
a
(読み込み '')
(読み込み 'b')
(読み込み 'c')
['b', 'c']
[]

yield from サブジェネレーター は、サブジェネレーターの値をそのまま順に返します。サブジェネレーターが return した値は、yield from 式の値になります。

内包表記の中で作ったラムダ式は、変数の値を呼び出したときに参照します (遅延束縛)。[lambda: i for i in range(3)] の 3 つの関数はどれも 2 を返します。作った時点の値を使うには lambda i=i: i のようにデフォルト引数に入れます。

デコレーター

デコレーターは、関数を受け取って別の関数を返す関数です。@deco を付けた関数定義は、定義の直後に func = deco(func) を 1 回だけ実行するのと同じ意味です。重ねて付けると、関数に近い (下の) ものから順に適用されます。

デコレーターが返す内側の関数 (wrapper) には、functools.wraps(func) を付けます。付けないと、関数名 (__name__) や docstring (__doc__) が wrapper のものに置き換わってしまいます。

引数を取るデコレーター (@retry(3) など) は、「デコレーターを返す関数」として、関数を 3 重に入れ子にして書きます。

Python
import functools​def retry(times):    def decorator(func):        @functools.wraps(func)        def wrapper(*args, **kwargs):            for n in range(1, times + 1):                try:                    return func(*args, **kwargs)                except ConnectionError:                    print(f"{n} 回目の失敗")            return "あきらめた"        return wrapper    return decorator​calls = 0​@retry(3)def fetch():    """データを取得する"""    global calls    calls += 1    if calls < 3:        raise ConnectionError    return "成功"​print(fetch(), fetch.__name__, fetch.__doc__)
ターミナル
python3 main.py
1 回目の失敗
2 回目の失敗
成功 fetch データを取得する

標準ライブラリにも、デコレーターとして使うものがあります。functools.cache・functools.lru_cache (戻り値のキャッシュ)、property・classmethod・staticmethod (メソッドの種類)、dataclasses.dataclass (クラスに付ける) などです。

試験でよくある引っかけ

  • except の順番

    except Exception: を先に書くと、後ろの except ValueError: には届きません。具体的な例外を先に書きます。

  • finally と return

    try 節で return しても、関数を抜ける前に finally 節が実行されます。

  • __exit__ の戻り値

    __exit__ が真の値を返すと、ブロック内の例外は外に伝わらず、with 文の次から処理が続きます。

  • マッピングパターンと余分なキー

    case {"type": "admin"}: は、ほかのキーを含む辞書にも一致します。

  • case 変数名: は何にでも一致する

    変数名だけのパターンは取り出しパターンで、値と比較するわけではありません。定数と比べたいときは Color.RED のようにドット付きの名前を使います。

  • 位置専用引数をキーワードで渡す

    / より前の引数をキーワードで渡すと TypeError です。

  • 変更可能なデフォルト値

    def f(items=[]) のリストは呼び出しをまたいで共有されます。

  • ジェネレーターは 1 回しか使えない

    最後まで進んだジェネレーターをもう一度 list() にすると空になります。in で調べた場合も、見つかるまでの要素は消費されます。

  • 重ねたデコレーターの順番

    @bold の下に @italic を書くと、bold(italic(func)) の順に適用されます。

問題で確認する

この分野の問題を、解説つきで読めます (登録不要)。

出典・参考

コード例は、実際に実行して結果を確認しています。