Ruleru
LLM を聞いて学ぶ

10/27(火) · 11:27

第7章 後半: 関数、クラス、そして語彙の小さな設計

『日本語技術教科書 Vol.0』の第7章 後半。関数、クラス、そして語彙の小さな設計を、2 人の掛け合いで解説する。

この回を聴く

AIこの記事は AI の Claude が書きました。

  • 関数では、名前の結び直しと中身の変更を区別し、既定値は定義の時点で 1 度だけ評価される。
  • クラスは属性の探索順序、継承と合成、dataclass と Protocol の限界を押さえて設計する。
  • イテレータは使い切ると空になり、深いコピーは共有と循環を保って複製する。語彙の設計は、保存したい意味から構造を選ぶ。

教材の 7.3 節から 7.5 節まで。

7.3.1〜7.3.4 関数とデータの流れ

教材の 7.3 の節では、呼び出しのとき、実引数の式を評価して、仮引数の名前をその対象に結ぶ。リストを渡しても自動では複製されない。関数の中でリストへ追加すれば呼び出し元から見えるが、仮引数の名前を別のリストへ結び直しても、呼び出し元の名前は動かない。a = a.append(3) と書くと、append の戻り値が None なので a が None を指す。元の入力を直接変える操作か、新しい値を返す変換かは、関数の名前や説明で明確にする。

既定値の式は、def の文が実行される定義の瞬間に評価され、呼ぶたびではない。空のリストを既定値にすると、1 回目と 2 回目の呼び出しが同じリストを使い、2 回目には 2 つの要素が入る。None を既定値にして本体で新しく作れば、呼び出しは独立する。可変長の引数では、*args に余りの位置引数が tuple で、**kwargs に余りのキーワード引数が dict で入る。1 つの引数へ位置とキーワードの両方で値を渡す呼び方は TypeError で、片方が勝つ決まりは無い。

クロージャでは、内側の関数が外側の名前の結び付きそのものを保持する。その時点の値のコピーを持つわけではない。カウンターを返す関数では、呼ぶたびに別のセルができ、nonlocal が代入を外側の束縛へ向ける。ラムダを並べたリストでは、3 つの関数が同じ変数 i を読むので、呼ぶ時点の値 2 がそろって返る。関数内で n += 1 と書くと、nonlocal が無い限り n は局所名と判定され、UnboundLocalError になる。

デコレータは、概念上は定義のあとに f = deco(f) と置き換えるのと同じである。飾りを付ける時と実際に呼ぶ時を分けて考える。wraps は名前や説明を引き継ぐだけで、引数の検証や戻り値の意味は保証しない。

7.4.1〜7.4.4 クラスの設計

クラスは型と共通の操作を定め、そこから作られる個々の個体がインスタンスだ。self は予約語ではなく、最初の引数の習慣上の名前にすぎない。属性を読む探索は、データ記述子、個体の属性辞書、非データ記述子と通常のクラス属性、の順に進む。どこにも無ければ、__getattr__ があればそこへ渡り、無ければ AttributeError となる。リストをクラス直下に置くと、全個体が同じリストを読む。

継承は元のクラスの振る舞いを受け継ぎ、合成は別のオブジェクトを属性に持って操作を呼ぶ。集計器が保存先を自分で作らず外から受け取る形は、依存性の注入と呼ばれる。書き込みの操作さえ同じなら、保存先を取り替えられる。継承の探索はメソッド解決順序に従い、super() は「直接の親」ではなく、その順序での次の候補を指す。

dataclass では、項目を宣言すると、初期化、表示、等しさの比較が自動で用意される。frozen=True は通常の属性代入を拒否するが、中のリストまでは凍結しない。型注釈が int でも、文字列の "4" が自動で変換されたり拒否されたりはしないので、値の検証は明示的に書く。Protocol が約束にするのは、ある基底クラスの子であることではなく、必要な操作を持っていることである。実行時に isinstance で確かめられるのは、おおむね属性の有無で、戻り値が何を意味するかは対象外になる。

7.5.1〜7.5.3 反復、コピー、語彙の設計

イテレータは次に返す場所を覚えており、列(リストのようなイテラブル)からは独立した位置を複数作れる。イテレータに iter をかけても同じ対象が返るだけで、先頭へは戻らない。ジェネレータを 1 度使い切ると、2 度目に取り出せるものは無い。結果を全部集めればその分のメモリが要り、終わりのないジェネレータをリストにすると終了しない。受け取る入力が何度も読める列なのか、1 回きりの流れなのかも、関数の約束事に入れておく。

深いコピーは、単純にすべてを別個体にするわけではない。書き換えられない対象は使い回され、すでに複製した物を記録する対応表が、内部の共有や循環を扱う。同じ行を 2 か所から参照するリストを深く複製すると、2 つの位置は同じ新しい行を共有する。ファイルのような外部の資源は、普通のデータと同じ扱いで複製することはできない。

教材の語彙の例は、文書の並びに list、語と番号の対応に dict、確定した結果の行に tuple を割り当てる。語が初めて出たときに次の番号を割り当て、空の文書も空の番号列として残す。入力は変更しないが、戻り値の番号列は可変である。文書の順を変えると番号が変わるので、学習済みの重みと語彙の組は別々に作り直せない。

7.5.4 API、例外、計測、テスト

公開の入口では、引数と戻り値に加えて、何を変更し、どう失敗するかも約束の内である。広く except してゼロを返すと、型の誤りやプログラムの不具合まで番号 0 として隠れる。教材は、辞書の欠損だけを独自の例外へ翻訳し、from で原因を残す例を挙げる。assert は最適化の実行で省かれうるので、公開入力の検証は任せない。プロファイラは時間や呼び出し回数の行き先を観測し、テストは呼び出し側との約束を確かめる。

次の第 8 章は、ファイル、文字コード、JSON、CSV の扱いと検証へ進む。

出典

  • オーナー(AI で作った教材、Web には公開していない) 日本語技術教科書 Vol.0 コンピュータからPython・機械学習・LLMへ 第7章 2026-10-18