STUDY GUIDE · オブジェクト指向型言語

期末試験対策 · 第9–10・12–14回本線

OOL
期末 教科書ノート

入門で用語を固めてから、演習と同型コードを手で書くドリルへ。中間(第2–7回)は別サイト。第11回は休講想定で欠番。

出題範囲 · 入門 · 手書きドリル · 試験ハブ

出題範囲と形式の推定

重要

期末試験の正式な問題形式は資料に明記されていない。以下は宿題・演習の型から推定した想定であり、断定ではない。

本線第9・10・12・13・14回+7/7追加(スコープ/ポリモーフィズム/標準・外部ライブラリ/tkinter/Canvas/継承復習)
復習第2–7回は中間サイトへ誘導: https://ool-midterm.pages.dev/
欠番 / OOS第1回(未入手)/第8回(中間試験日の可能性大)/第11回(休講想定・欠番)
日程メモ第14回資料: 7/21 休講、7/28 期末試験
推定形式(1) クラス実装+継承+ポリモーフィズム呼び出し (2) import/標準・外部ライブラリ (3) tkinter 部品+Var (4) Canvas 画像・move
狙い演習問題と同じ/ほぼ同じコードを白紙から書けること(用語暗記だけでは足りない)
答案型

期末でよく出る骨格チート

詳細は各ドリルの答案型。試験開始直後にこの形を思い出す。

# 継承+ポリ
class Parent: ...
class Child(Parent):
    def __init__(self, ...):
        super().__init__(...)
    def meth(self): ...
def call(obj): return obj.meth()

# import
import random / import math / from PIL import Image
import tkinter as tk

# GUI
base = tk.Tk()
# Widget + Var + pack + command
base.mainloop()

# Canvas 移動
canv.move(tag, dx, dy); canv.update()
# 絶対座標
canv.coords(tag, x, y)

今日のモード

初見の既定は「学ぶ」。ドリル強制はしない(expertise reversal)。

中間サイトへの誘導

第2–7回(クラス・self・継承の土台)の厚い解説は中間専用サイトに分離した。URL を増やさないため、期末は後半本線に集中する。

中間教科書を開く

Pr

入門 — 期末用語を金標準で固める

本編のコードトレースに入る前に、試験用語をここで読み切る。薄い要約禁止。各カードに定義・なぜ・イメージ・仕組み・答案一言を揃えた。

中間の土台(要約)+期末本線用語
01

スコープ(すこーぷ)とは、

なぜ今学ぶか: 期末以降のクラス・関数コードでは、見た目同じ変数名がローカル/グローバル/self で別物になる。ここを落とすと「なぜエラー?」が一生続く。

変数が「どこまで見えるか」という有効範囲のこと。同じ名前でも場所が違えば別物になりうる。

別名: 有効範囲。英語 scope。

関数の外で v=10、関数内で v=20 を代入

関数内 print は 20、関数外 print は 10(または未定義)

仕組み: 代入した場所のブロックがスコープを決める。関数内の代入はローカル、ファイル先頭はグローバル、self. 付きはインスタンス。

たとえ話: 教室の黒板(グローバル)と、自分のノート(ローカル)。ノートに書いた答えは隣の席から見えない。

具体例
v = 10
def printer():
    v = 20
    print(v)  # 20(ローカル)
printer()
print(v)     # 10(グローバル)
よくある誤解

「同じ名前だから同じ変数」と思い込むこと。関数内で代入した瞬間、その関数ではローカル扱いになる。

試験答え方: 「スコープ=変数の有効範囲。ローカルは関数内のみ、グローバルはファイル全体」と1文で書く。

02

ローカル変数とグローバル変数とは、

なぜ: 宿題の関数・メソッドで「外から見えない」「中から見える」を説明できる必要がある。

ローカルは関数ブロック内だけの変数。グローバルはファイルのトップレベルで定義された変数。

別名: local / global。

def f(): の中でだけ定義した area

area は消える(外側から参照するとエラー)

仕組み: ローカルはブロックを出ると寿命が尽きたとみなされる。グローバルはファイル実行中ずっと名前空間に残る。

具体例
種類定義場所外から
ローカル関数内不可
グローバルトップレベル
よくある誤解

クラス内メソッドのローカル area と self.area(インスタンス変数)を混同しない。

試験答え方: 表で「定義場所/外から使えるか」を対比して書く。

03

インスタンス変数とクラス変数とは、

なぜ: 第7回〜第9回で優先順位が問われる。期末の GameCharacter も self.job, self.life が本体。

インスタンス変数は個体ごとのデータ(self.x)。クラス変数はクラス全体で共有するデータ。

別名: インスタンス属性 / クラス属性。

騎士Aと魔法使いBが同じクラス

A.life と B.life は別物(インスタンス変数)

仕組み: メソッド内の self.付きがインスタンス変数。クラス直下で代入したものがクラス変数。同名ならインスタンス側が優先されやすい。

具体例
class Circle:
    x = 0  # クラス変数
    def __init__(self, r):
        self.r = r  # インスタンス変数
よくある誤解

クラス変数を self.x = … で上書きすると、そのインスタンスだけ別物になる。

試験答え方: 「self.変数=個体ごと/クラス.変数=共有」と対で書く。

04

ポリモーフィズム(ぽりもーふぃずむ)とは、

なぜ: 期末宿題の Animal.cry / Book.display の核心。ここが弱いと「ただの別関数呼び出し」で終わる。

同じ操作の名前で、相手の型ごとに違う処理を呼び出せること。呼び出し側を型ごとに書き換えなくてよい。

別名: 多態性。講義では「同じボタンで車は発進するが中身は違う」たとえ。

hero.speak() と enemy.speak() を別々に書く

def intro(obj): return obj.speak()

仕組み: 各クラスに同名メソッドを用意(必要ならオーバーライド)。呼び手は obj.メソッド() だけ書く。実行時に実体の型の実装が選ばれる。

車の発進ボタンはどれも「Aボタン」。中身はゆっくり発進でも急加速でも、運転手の操作は同じ。

よくある誤解

「継承が必須」ではない。異なるクラスに同名メソッドがあればポリモーフィズムの考え方は使える。ただし講義演習は継承+オーバーライドが多い。

試験答え方: 「呼び出し側を変えず、同じメソッド名で型ごとの処理を実行できること」+短いコード例。

05

オーバーライドとは、

なぜ: Dog.cry が「わんわん」になるのはオーバーライド。ポリモーフィズムの実装手段。

親クラスで定義したメソッドを、子クラスで同名メソッドとして上書きすること。

別名: 上書き。オーバーロード(引数違いの多重定義)とは別物。

親 Animal.cry → 「鳴く」

Dog.cry → 「わんわん」

仕組み: 子に同名メソッドを書くと、そのインスタンスでは親の実装より子が優先される。親の続きを使いたいときは super()。

よくある誤解

オーバーロードと混同しない。Python は基本的に後から定義した同名が上書きになる。

試験答え方: 「親の同名メソッドを子で上書きすること」と定義し、例を1つ添える。

06

標準ライブラリ/モジュール/パッケージとは、

なぜ: random / math / calendar / datetime / tkinter が期末本線。import の書き方がそのまま点数になる。

標準ライブラリは Python 同梱の道具箱。モジュールは .py の道具ファイル。パッケージはモジュールをまとめたフォルダ。

別名: 標準ライブラリ ≠ 組み込み関数(abs 等は import 不要)。

道具箱(ライブラリ)

モジュール=個別の道具、パッケージ=セット売り

仕組み: import 名前 で読み込む。as で別名、from … import … で一部だけ取り込む。

具体例
import random
from math import sqrt, pi
import calendar as cal
よくある誤解

random は標準なのに pip が要ると勘違いしがち。逆に Pillow は外部で pip が要る。

試験答え方: 「標準=同梱だが import 必要/組み込み=import 不要」を対比。

07

Pillow(ぴろー)とは、

なぜ: 第10回の本線。pip install と Image.open / resize / save が宿題になる。

画像を開いたり変形したりする外部ライブラリ。インストール名は Pillow、import は PIL。

別名: PIL(歴史的名前)。from PIL import Image。

pip install Pillow

img = Image.open('a.png')

仕組み: 外部なので (1) pip で入れる (2) import する。以降は標準モジュールと同様に使う。

よくある誤解

import pillow とは書かない。パッケージ表示名と import 名が違う。

試験答え方: 「外部ライブラリ。pip install Pillow。使うときは from PIL import Image」。

08

tkinter(てぃーけいインター)とは、

なぜ: 第12〜14回の本線。期末は「部品を置く+押したら何をするか」の2段が問われる。

Python 標準の GUI ライブラリ。ウィンドウを作り、ボタンやラベルなどの部品を置く。

別名: Tkinter / ToolKit Interface。

import tkinter as tk → Tk() → 部品を pack

画面が表示され続け、クリックを待つ

仕組み: (1) ベース画面 Tk (2) Button 等のウィジェットを生成 (3) pack で配置 (4) command で処理を結ぶ (5) mainloop。

具体例
import tkinter as tk
base = tk.Tk()
btn = tk.Button(base, text='PUSH!!')
btn.pack()
base.mainloop()

試験答え方: 「標準GUI。Tk+ウィジェット+pack+mainloop」の流れを書く。

09

ウィジェット変数(StringVar / BooleanVar / IntVar)とは、

なぜ: 入力欄の文字やチェック状態を get/set で読み書きするのが宿題の型。

Entry・チェック・ラジオなどと連動して、画面の入力状態を Python 側で持つ専用の変数クラス。

別名: コントロール変数。textvariable / variable オプションで結ぶ。

ユーザーが Entry に文字を打つ

moji.get() で文字列を取得

仕組み: StringVar=文字列、BooleanVar=真偽、IntVar=整数(ラジオの value)。set で初期値、get で取得。

よくある誤解

普通の str 変数を textvariable に渡しても連動しない。必ず *Var インスタンス。

試験答え方: 用途ごとにどの Var かを選び、「variable=…」で結ぶと答える。

10

Canvas(きゃんばす)とは、

なぜ: 第13–14回。画像の中心座標・png 対応が落とし穴。

線・円・画像・文字を描くための描画面ウィジェット。ゲームやおみくじの土台。

別名: キャンバス。create_image / create_text / move / coords。

空のウインドウ

キャラ画像が座標 (x,y) の中心に表示

仕組み: Canvas(幅,高さ) → PhotoImage で画像読込 → create_image(x,y,image=…) → タグを付けて move/coords。

よくある誤解

create_image(0,0) だと画像の半分が画面外に出やすい。中心=幅/2, 高さ/2 を意識。

試験答え方: 「描画面。画像は中心座標。png 推奨(jpg 注意)」。

11

move と coords とは、

なぜ: 攻撃ボタン課題の核心。どちらを使うかで答えが変わる。

move は相対移動、coords は絶対座標への置き直し。攻撃アニメは主に move+update。

別名: 相対移動 / 絶対配置。

図形が (200,300)

中心がおよそ (210,350) へ相対移動

仕組み: move(タグ, dx, dy)。coords(タグ, x, y) は中心を (x,y) に設定。直後に update() で画面反映。

具体例
canv.move('rect_1', 10, 50)
canv.update()
canv.coords('rect_1', 200, 300)

試験答え方: 「move=相対、coords=絶対。アニメ中は update を挟む」。

12

継承と super() とは、

なぜ: 第14回 Book / Magazine / Comic が期末直前の総復習。

継承は親の設計を子が引き継ぐこと。super() は親のメソッド(特に __init__ / display)を子から呼ぶ道具。

別名: class 子(親): 。親コンストラクタ呼び出し。

Book に name, price, display

super().__init__ と super().display() で重複を避ける

仕組み: 子の __init__ で super().__init__(共通引数)。display も共通部分は super().display()。

よくある誤解

親引数を子で再代入だけして super を忘れると、親側の初期化が走らない。

試験答え方: 「括弧に親名=継承。共通初期化は super().__init__」。

00

中間範囲(クラス・self・継承)の土台とは、

なぜ: 期末サイトは本線を後半に絞る。復習は中間サイトを正本にする。

期末は中間のクラス/self/継承の上に、スコープ・ライブラリ・GUI が載る。土台が揺れると後半が全部崩れる。

別名: 第2–7回。詳細は中間サイトへ。

クラス・インスタンス・self が曖昧

期末の GameCharacter / Book が読める

仕組み: 設計図=クラス、実体=インスタンス、メソッド第1引数=self(呼ぶ側は渡さない)、子(親)=継承。

具体例

中間教科書: https://ool-midterm.pages.dev/

試験答え方: 中間用語は中間サイトの定義で答える。期末答案では後半トピックを優先。

試験項目ハブ

A

スコープ

ローカル/グローバル/self

B

ポリモーフィズム

同名メソッド・オーバーライド

本編の読み順

  1. §A スコープ
  2. §B ポリモーフィズム
  3. §C 標準・外部ライブラリ
  4. §D tkinter
  5. §E Canvas・GameCharacter
  6. §F Book 継承(第14回)

§A スコープ

§A-1 形式:4種の変数の読み下し

記号に入る前に

記号に入る前に: 「どこで作ったか」だけ見れば種類が決まる。self の有無が最大の分岐。

種類書き方読み下し
ローカルarea = …(メソッド内・selfなし)この関数の一時メモ
グローバルファイル先頭の v = …ファイル全体の共有メモ
インスタンスself.r = rこの個体の属性
クラスクラス直下 x = 0クラス全員の共有属性

アクセス: 外からインスタンス変数は obj.r。クラス変数は Circle.x または(読取なら)self.x

§A-2 形式:関数スコープの規則

関数ブロック内で代入された名前は、その関数のローカルになる。関数外の同名グローバルとは別物。

v = 10          # global
def printer():
    v = 20      # local(関数内だけ)
    print(v)

§A-3 形式:self 付き vs クラス直下

class Circle:
    x = 0                 # クラス変数
    def __init__(self, r):
        self.r = r        # インスタンス変数
    def area(self):
        area = 3.14*self.r**2  # ローカル(外から見えない)
        return area

例題A(L3): スコープをトレースせよ

与件: 次のコードがある。

v = 10
def printer():
    v = 20
    print(v)
printer()
print(v)
求めよ: (1) printer() 実行時に表示される値 (2) 直後の print(v) の値。理由も書け。

なぜ今この計算か: 同名でもスコープが違えば別変数。試験では「表示値+理由」セットが答案になる。

求めるもの: (1)(2)の表示値と、ローカル/グローバルの対応
使う式 / 使う定義: 規則: 関数内の代入 → ローカル。トップレベル → グローバル。
  1. トップレベルで v=10 → グローバル v が 10。
  2. printer() に入る。関数内 v=20 はローカル v を作る(グローバルはまだ 10)。
  3. 関数内 print(v) はローカルを見る → 20
  4. 関数を抜けるとローカル v は消える。
  5. 外側 print(v) はグローバル → 10
(1) 20 (2) 10

答案文: printer 内の v はローカルなので 20 が表示され、外側の print はグローバルの 10 を表示する。

部分点: 表示値だけ合って理由なし → 半分。ローカル/グローバルの語が出れば加点。

考察: 考察: 数値 20 と 10 の差は「代入した場所」だけを見れば説明できる。restart なしで続けて実行すると状態が汚れやすい点にも注意。

§B ポリモーフィズム

§B-1 形式:同名メソッド呼び出し

記号に入る前に

記号に入る前に: 運転手は「発進ボタン」だけ知っていればよい。車種ごとのエンジン制御は車側が持つ。

def self_introduction(obj):
    return obj.speak()  # 呼び出し側は型を気にしない

各クラスに speak(または cry)があれば、同じ関数で扱える。

§B-2 形式:オーバーライド

class Animal:
    def cry(self):
        return "鳴く"
class Dog(Animal):
    def cry(self):          # オーバーライド
        return "わんわん"

例題B(L3): Animal ポリモーフィズムを実装せよ

与件(第9回演習): 1. 親 Animalcry"鳴く" を返す。 2. 子 Dog"わんわん"、子 Snake"シャー"。 3. 各子の cry をポリモーフィズムの考えで実行せよ。 求めよ: 完成コードと、共通関数から呼ぶ実行例。

なぜ今この手順か: 宿題同型。定義→オーバーライド→共通呼び出しの3段が答案フォーマット。

求めるもの: 3クラス+共通呼び出しで各 cry を実行するプログラム
使う式 / 使う定義: 使う定義: 継承 class Dog(Animal)、オーバーライド、共通関数 def play(obj): return obj.cry()
  1. 親を定義:
    class Animal:\n    def cry(self):\n        return "鳴く"
  2. 子 Dog:
    class Dog(Animal):\n    def cry(self):\n        return "わんわん"
  3. 子 Snake: 同様に return "シャー"
  4. 共通関数:
    def play(obj):\n    return obj.cry()
  5. 実行: print(play(Dog())); print(play(Snake())) → わんわん / シャー。
Dog→わんわん、Snake→シャー(共通関数 play 経由)

答案文: 各子で cry をオーバーライドし、play(obj) から同じ呼び出しで結果を得た。

部分点: クラス定義のみで共通関数なし → ポリモーフィズム説明不足で減点想定。

考察: 考察: 呼び出し行が1種類なのに出力が分かれること自体が、ポリモーフィズムの証拠になる。

答案型

例題B 完成コード(写経用)

ドリル②へ進む前に一度写経。細部は 手書きドリル

class Animal:
    def cry(self):
        return "鳴く"
class Dog(Animal):
    def cry(self):
        return "わんわん"
class Snake(Animal):
    def cry(self):
        return "シャー"
def play(obj):
    return obj.cry()
print(play(Dog())); print(play(Snake()))

例題B2(L3): オーバーライドの前後を答えよ

与件: Animal().cry() は「鳴く」、Dog().cry() は「わんわん」。求めよ: Dog 側で何をしたか(用語+1行コードの意味)。

なぜ今この問か: 用語「オーバーライド」を答案に書けるか確認する。

求めるもの: 用語名と、子で同名メソッドを定義したことの説明
使う式 / 使う定義: 定義: 親メソッドの上書き=オーバーライド
  1. 親に cry があることを確認。
  2. 子クラス本文に同名 def cry(self): を書く。
  3. 子インスタンスでは子の実装が選ばれる。
  4. これをオーバーライドと呼ぶ。
オーバーライド(親 cry を子で上書き)

答案文: Dog は親の cry を同名メソッドで上書き(オーバーライド)し、「わんわん」を返す。

部分点: 「継承した」だけ → 不十分。上書きに言及すること。

考察: 考察: 継承だけでは親の「鳴く」のまま。出力が変わった瞬間がオーバーライド。

§C ライブラリ

§C-1 形式:import の3パターン

記号に入る前に

記号に入る前に: 標準ライブラリは「最初からカバンに入っているが、使うには取り出す(import)」。

書き方意味
import randomモジュールごと。以降 random.randint
import calendar as cal別名
from math import sqrt, pi一部だけ。以降 sqrt(…)

組み込み abs は import 不要。math.fabs は import 必要。

§C-2 形式:外部ライブラリ Pillow

  1. pip install Pillow
  2. from PIL import Image
  3. img = Image.open(path) → 変形・保存

例題C1(L3): サイコロ差を表示せよ

与件(第9回演習2): 1〜6の乱数を2つ(di1, di2)。一致なら「同じ数」、違えば差の絶対値を表示。絶対値は math を import して使う。求めよ: 完成手順と表示分岐。

なぜ今この手順か: random と math を同時に使う宿題同型。

求めるもの: 一致判定と差の絶対値表示
使う式 / 使う定義: random.randint(1,6) と math.fabs または abs(指定に従い math)
  1. import randomimport math
  2. di1 = random.randint(1, 6)di2 = random.randint(1, 6)
  3. if di1 == di2: → print「同じ数」。
  4. else → print(math.fabs(di1 - di2))(または課題指定の絶対値関数)。
  5. 実行して一致/不一致の両ケースを確認。
一致→「同じ数」、不一致→|di1-di2|

答案文: randint で2個振り、等値なら同じ数、否则 math で絶対値差を表示する。

部分点: random のみで abs 組み込みだけ → 課題が math 指定なら減点想定。

考察: 考察: 差の符号が正負どちらでも絶対値なら同じ。fabs は float を返す点に注意。

答案型

例題C1 完成コード

ドリル③ で穴埋め→solo。

import random
import math
di1 = random.randint(1, 6)
di2 = random.randint(1, 6)
if di1 == di2:
    print("同じ数")
else:
    print(math.fabs(di1 - di2))

例題C2(L3): Pillow で画像を開く

与件: 外部ライブラリ Pillow を使い、ファイル sample.png を開いてサイズを表示したい。求めよ: インストール確認から表示までの手順。

なぜ今この手順か: 外部ライブラリは「入れる→import→使う」の3点が採点ポイント。

求めるもの: Image.open まで到達する最小コード
使う式 / 使う定義: pip install Pillow / from PIL import Image / Image.open
  1. 端末で pip install Pillow(未導入時)。
  2. pip show Pillow または from PIL import Image が通るか確認。
  3. コード: from PIL import Image
  4. img = Image.open('sample.png')
  5. print(img.size) で (幅, 高さ) を確認。
from PIL import Image → Image.open('sample.png')

答案文: Pillow を導入し PIL.Image で sample.png を開いた。

部分点: パッケージ名を小文字で import した → 誤り(正: from PIL import Image)。

考察: 考察: パッケージ名 Pillow と import 名 PIL のズレはよく出る引っかけ。

§D tkinter

§D-1 形式:Tk → ウィジェット → pack → mainloop

記号に入る前に

記号に入る前に: GUI は「箱を出す」「部品を置く」「押されたら動く」「表示を維持」の4拍子。

import tkinter as tk
base = tk.Tk()
button = tk.Button(base, text="PUSH!!", command=push)
button.pack(side=tk.TOP)
base.mainloop()

pack の side: TOP / LEFT / RIGHT / BOTTOM。anchor で方角寄せ。

§D-2 形式:*Var と get/set

クラス用途典型
StringVarEntry / Label 文字textvariable=moji
BooleanVarCheckbuttonvariable=bln / set(True)
IntVarRadiobutton の valuevariable=int_v

例題D1(L3): ボタンを左から並べよ

与件: Tk ウィンドウに Button を2つ置き、左から並べる。クリックで print('ok')。求めよ: 最小コード。

なぜ今この手順か: pack(side=LEFT) と command の結びが基本点。

求めるもの: LEFT 配置の2ボタン GUI
使う式 / 使う定義: tk.Tk / tk.Button / pack(side=tk.LEFT) / mainloop
  1. import tkinter as tk
  2. base = tk.Tk()
  3. def ok(): print('ok') を定義。
  4. Button を2つ作り pack(side=tk.LEFT)
  5. base.mainloop()
2ボタンが横並び、クリックで ok 表示

答案文: Tk 上に Button を LEFT で pack し、command で ok を結んだ。

部分点: mainloop 忘れ → 画面が一瞬で消える/出ない。

考察: 考察: side を指定しないと TOP(縦積み)になる。見た目で採点されやすい。

例題D2(L3): チェック3つ+表示ボタン

与件(第12回練習1): コーヒー・お茶・ジュースをチェック可能にし、ボタンで選択商品を画面表示。求めよ: BooleanVar×3 と表示更新の手順。

なぜ今この手順か: 宿題同型。Var・Checkbutton・Button の連携が本体。

求めるもの: 選択中の飲み物名を Label 等に出す UI
使う式 / 使う定義: BooleanVar + Checkbutton(variable=…) + get() で分岐
  1. base = Tk()。表示用 StringVar または Label を用意。
  2. b_coffee, b_tea, b_juice = BooleanVar() を3つ。
  3. Checkbutton(…, text='コーヒー', variable=b_coffee) を同様に3つ pack。
  4. ボタン command で各 get() を見て、True の名前を連結。
  5. Label / StringVar に結果を set して表示。mainloop。
チェックした飲み物名がボタン押下で表示される

答案文: BooleanVar と Checkbutton を結び、get 結果から表示文字列を組み立てた。

部分点: Checkbutton だけ置いて get しない → 状態を読めていない。

考察: 考察: 練習2は for + 辞書で同じUIを短くする。重複コード削減が次の加点ポイント。

答案型

例題D2 完成コード(for+辞書版)

ドリル⑧ で手書き。

import tkinter as tk
base = tk.Tk()
drink = {0: "コーヒー", 1: "お茶", 2: "ジュース"}
flags = [tk.BooleanVar() for _ in drink]
out = tk.StringVar()
for i in range(len(drink)):
    tk.Checkbutton(base, text=drink[i], variable=flags[i]).pack(anchor=tk.W)
def show():
    out.set(", ".join(drink[i] for i in drink if flags[i].get()))
tk.Button(base, text="表示", command=show).pack()
tk.Label(base, textvariable=out).pack()
base.mainloop()

§E Canvas

§E-1 形式:Canvas と create_image

記号に入る前に

記号に入る前に: Canvas はスケッチブック。画像の「ピン留め位置」はだいたい中心。

canv = tk.Canvas(base, width=400, height=560)
img = tk.PhotoImage(file="chara.png")  # png
canv.create_image(200, 300, image=img, tags="rect_1")

tkinter は png 対応、jpg は講義で非対応と注意。

§E-2 形式:move / coords / update

canv.move("rect_1", 10, 50)   # 相対
canv.update()
canv.coords("rect_1", 200, 300)  # 絶対(中心)

例題E1(L3): 画像をキャンバス中央付近に置け

与件: 幅400×高さ560の Canvas。350×410 の png を見切れにくく置きたい。求めよ: create_image の座標の選び方。

なぜ今この計算か: 中心指定を間違えると半分欠ける。

求めるもの: 適切な (x,y) の目安
使う式 / 使う定義: create_image の x,y は画像中心。Canvas 中央はおおよそ (200, 280) 前後
  1. Canvas サイズ (400,560) を確認。
  2. 中央の目安 x=200, y=280〜300。
  3. PhotoImage で png を読む。
  4. create_image(200, 300, image=img)。
  5. 端が見切れたら y を調整(講義例は 200,300)。
例: create_image(200, 300, image=img)

答案文: Canvas 中央付近を中心座標にして png を配置した。

部分点: (0,0) 配置のまま → 大きく欠ける。

考察: 考察: 画像サイズが Canvas より大きいときは縮小か Canvas 拡大が先。

例題E2(L3): 攻撃ボタンで相手方向へ移動

与件(第13回演習): 左右キャラに攻撃ボタン。押した側の画像を相手方向へ move。求めよ: 左側ボタン用の相対移動の考え方。

なぜ今この手順か: 追加資料の攻撃描画と同型。左右で dx の符号が逆。

求めるもの: 左キャラが右方向へ相対移動するコマンド
使う式 / 使う定義: canv.move(tag, dx, dy) + update。左→右なら dx>0
  1. 左キャラのタグ(例 rect_1)を確認。
  2. 相手は右にいるので dx を正(例 +10)、dy は 0 または小。
  3. ボタン command で move を数回、またはループ。
  4. 各 step の後に canv.update()
  5. 必要なら元座標へ coords で戻す/ダメージ演出へ進む(第14回)。
左攻撃: move(tag, +dx, 0) 連打+update

答案文: 攻撃ボタンで自分のタグを相手方向へ相対移動させ、update で描画した。

部分点: coords だけ使う/update なし → 動きが見えない or 意図と違う。

考察: 考察: move は相対なので「今どこにいるか」に依存する。初期位置を固定してから試す。

答案型

例題E2 攻撃の答案型

ドリル⑫ で左右符号を手書き。

def attack_left():
    for _ in range(8):
        canv.move("left", 12, 0)   # 右へ +dx
        canv.update()
def attack_right():
    for _ in range(8):
        canv.move("right", -12, 0)  # 左へ -dx
        canv.update()

§F 継承総復習

§F-1 形式:Book 系の継承設計

記号に入る前に

記号に入る前に: 共通(タイトル・値段)は親、差分(月号・巻)は子。display も共通部分は super。

class Book:
    def __init__(self, name, price):
        self.name, self.price = name, price
    def display(self):
        print(self.name, self.price)

class Magazine(Book):
    def __init__(self, name, price, keyword, month):
        super().__init__(name, price)
        self.keyword, self.month = keyword, month
    def display(self):
        super().display()
        print(self.keyword, self.month)

例題F(L3): Book / Magazine / Comic

与件(第14回練習2): - Magazine: 月刊釣り名人, 1000, 釣りスポット, 8月号 → m1 - Comic: 名探偵コナン, 500, 推理もの, 10巻 → c1 最後に display をポリモーフィズムで同じ関数から実行。求めよ: クラス骨子と呼び出し。

なぜ今この手順か: 期末直前の総合。継承・super・ポリモーフィズムが1問に圧縮されている。

求めるもの: m1/c1 の display を共通関数から実行
使う式 / 使う定義: class 子(Book) + super().__init__ + super().display + def show(obj): obj.display()
  1. Book に name, price と display を実装。
  2. Magazine(Book): super().__init__ 後に keyword, month。display で super().display() のあと追加表示。
  3. Comic(Book): 同様に keyword, volume。
  4. m1 = Magazine('月刊釣り名人', 1000, '釣りスポット', '8月号')
  5. c1 = Comic('名探偵コナン', 500, '推理もの', '10巻')
  6. def show(obj): obj.display() として show(m1); show(c1)
show(m1)/show(c1) で各 display が走る

答案文: 親 Book を継承した2子を super で初期化し、共通 show から display した。

部分点: super なしで親フィールドだけ手動代入 → 課題意図から外れる減点想定。

考察: 考察: 出力が親子で分かれることと、呼び出しが show(obj) 一種類であることが両方必要。

答案型

例題F 完成コード骨子

ドリル⑮ で宿題引数どおり solo。

class Book:
    def __init__(self, name, price):
        self.name, self.price = name, price
    def display(self):
        print(self.name, self.price)
class Magazine(Book):
    def __init__(self, name, price, keyword, month):
        super().__init__(name, price)
        self.keyword, self.month = keyword, month
    def display(self):
        super().display()
        print(self.keyword, self.month)
# Comic 同様 → show(m1); show(c1)

手書きドリル(worked → faded → solo)

①完成例(worked)は下の各ドリルと本編 L3。②フェード(faded)は穴埋め。③自力(solo)は白紙でノートに書く。L3 と同数値・同文言のコピペ禁止(L4 は別 surface)。

ドリル一覧へ

手で書くドリル一覧

期末は演習と同じ/ほぼ同じコードを白紙から書ける力が本命。 入門用語は土台。主役は下のドリル(問題文→答案型→worked→faded→solo)。

テーマドリル
第9スコープ・面積ポリ・Animal・サイコロ Circle/Square · Animal · dice
第10Pillow・time・足し算タイマー Pillow · mondai計測
第12チェック/ラジオ+for 飲み物Check · ランチRadio
第13+追加GameCharacter・攻撃move GameCharacter · 攻撃ボタン
第14おみくじ・Book継承 おみくじ · Book系
回し方 ①答案型を暗唱 → ②workedを写経1回 → ③faded穴埋め → ④soloをノートに手書き → ⑤L4類題で別文言。

ドリル① CircleArea / SquareArea

資料準拠: OOL_6月16日 練習問題1(宿題)

問題文
  1. CircleArea: コンストラクタ引数 r。面積 cc を返す area
  2. 正方形 SquareArea: 引数 a。面積 ss を返す area
  3. どちらも同じ cal_area 関数から呼べるようにする。
答案型

この問題の答案型(骨格)

class CircleArea:
    def __init__(self, r): ...
    def area(self): ...
class SquareArea:
    def __init__(self, a): ...
    def area(self): ...
def cal_area(obj):
    return obj.area()
① worked — 完成コード+解説
class CircleArea:
    def __init__(self, r):
        self.r = r
    def area(self):
        cc = 3.14 * self.r ** 2
        return cc

class SquareArea:
    def __init__(self, a):
        self.a = a
    def area(self):
        ss = self.a ** 2
        return ss

def cal_area(obj):
    return obj.area()

print(cal_area(CircleArea(2)))
print(cal_area(SquareArea(3)))

共通はメソッド名 area と呼び出し側 cal_area(obj)。円/正方形の中身は別。変数名 cc/ss は宿題表記に合わせた。

② faded — 穴埋め(手で埋めてから開く)
class CircleArea:
    def __init__(self, r):
        self.r = r
    def area(self):
        cc = ___ * self.r ** 2
        return cc

class SquareArea:
    def __init__(self, a):
        self.___ = a
    def area(self):
        return self.a ** ___

def cal_area(obj):
    return obj.___()

ヒント: 円は 3.14。正方形は辺の2乗。cal_area は area を呼ぶだけ。

穴埋め解答
3.14 / a / 2 / area
③ solo — 白紙で書く

ノートにクラス2つ+cal_area を白紙で書け。数値は r=5, a=4 で動かしたつもりで答えも書け。

solo 解答例(書いたあと照合)
# 例: cal_area(CircleArea(5)) → 78.5
# cal_area(SquareArea(4)) → 16
# (実装は worked と同型。数値だけ変える)
よくあるバグ
  • area を片方だけ定義して cal_area で AttributeError
  • cc/ss を self なしローカルにしたあと return 忘れ
  • cal_area を各クラス専用に2つ書く(ポリモーフィズムになっていない)
採点ポイント
  • 両クラスに area がある
  • cal_area(obj) が1つで両方呼べる
  • コンストラクタで self.r / self.a を保持

ドリル② Animal / Dog / Snake

資料準拠: OOL_6月16日 演習問題1(宿題)※文言ほぼそのまま

問題文
  1. Animalcry"鳴く" を返す。
  2. Dog"わんわん"
  3. Snake"シャー"
  4. 各子の cry をポリモーフィズムの考えに基づいたコードで実行。
答案型

この問題の答案型(骨格)

class Animal:
    def cry(self): ...
class Dog(Animal):
    def cry(self): ...
class Snake(Animal):
    def cry(self): ...
def play(obj):
    return obj.cry()
① worked — 完成コード+解説
class Animal:
    def cry(self):
        return "鳴く"

class Dog(Animal):
    def cry(self):
        return "わんわん"

class Snake(Animal):
    def cry(self):
        return "シャー"

def play(obj):
    return obj.cry()

print(play(Dog()))
print(play(Snake()))
print(play(Animal()))

呼び出し行は play(obj) 一種類。出力が分かれること自体が答案の証拠。

② faded — 穴埋め(手で埋めてから開く)
class Animal:
    def cry(self):
        return "___"

class Dog(Animal):
    def ___(self):
        return "わんわん"

class Snake(___):
    def cry(self):
        return "シャー"

def play(obj):
    return obj.___()

ヒント: 親の戻り値/オーバーライドするメソッド名/親クラス名/共通呼び出し。

穴埋め解答
鳴く / cry / Animal / cry
③ solo — 白紙で書く

ヒントなしで3クラス+共通関数を手書き。実行結果3行も予想して書け。

solo 解答例(書いたあと照合)
わんわん\nシャー\n鳴く
よくあるバグ
  • オーバーロードと書いてしまう(用語ミス)
  • Dog/Snake ごとに別関数を呼ぶ(共通関数なし)
  • 継承せず独立クラスだけ作る
採点ポイント
  • 継承関係が正しい
  • cry のオーバーライド
  • 共通関数(または同型呼び出し)でポリモーフィズム実行

ドリル③ サイコロ2個+絶対値差

資料準拠: OOL_6月16日 演習問題2(宿題)

問題文 random で 1〜6 の乱数を2つ(di1, di2)。一致なら「同じ数」、違えば差の絶対値。 絶対値は math モジュールを import して使う。
答案型

この問題の答案型(骨格)

import random
import math
di1 = random.randint(1, 6)
di2 = random.randint(1, 6)
if di1 == di2:
    print("同じ数")
else:
    print(math.fabs(di1 - di2))
① worked — 完成コード+解説
import random
import math

di1 = random.randint(1, 6)
di2 = random.randint(1, 6)
print(di1, di2)  # 確認用(任意)

if di1 == di2:
    print("同じ数")
else:
    print(math.fabs(di1 - di2))

課題は math 指定。組み込み abs だけだと減点されうる。fabs は float を返す。

② faded — 穴埋め(手で埋めてから開く)
import ___
import math
di1 = random.randint(___, ___)
di2 = random.randint(1, 6)
if di1 ___ di2:
    print("同じ数")
else:
    print(math.___(di1 - di2))

ヒント: モジュール名/範囲/比較演算子/絶対値関数名。

穴埋め解答
random / 1 / 6 / == / fabs
③ solo — 白紙で書く

import から if/else までノートに書け。範囲は宿題どおり 1〜6。

solo 解答例(書いたあと照合)
worked と同型。実行結果は乱数依存。
よくあるバグ
  • randint(1, 5) や range と混同して 6 が出ない
  • math を import せず abs だけ
  • 差を絶対値にせず負のまま表示
採点ポイント
  • import random と import math
  • randint(1,6)×2
  • 一致/差の分岐
  • math の絶対値

ドリル④(L4類題)スコープ別数値

グローバル n=3。関数内 n=9 して print。外側で print。表示は?(L3 の 10/20 とは別)

ヒント(フェード)

関数内代入=ローカル。外側はグローバルのまま。

解答・誤答パターン

答え: 関数内 9、外側 3

よくある落とし穴: 両方 9(グローバル上書きと誤解)

ドリル⑤ Pillow 開く・表示・保存

資料準拠: OOL_6月23日 サンプル+導入確認

問題文 Pillow を使い hana.jpg(同フォルダ想定)を開き、表示し、グレースケールにして hana_gray.jpg に保存せよ。
答案型

この問題の答案型(骨格)

from PIL import Image
img = Image.open("hana.jpg")
img.show()
gray = img.convert("L")
gray.save("hana_gray.jpg")
① worked — 完成コード+解説
# 事前: pip install Pillow
from PIL import Image

img = Image.open("hana.jpg")
print(img.size, img.height, img.width)
img.show()

gray = img.convert("L")
gray.save("hana_gray.jpg")
gray.show()

パッケージ名は Pillow、import は PIL。属性 size/height は img オブジェクト側。

② faded — 穴埋め(手で埋めてから開く)
from ___ import Image
img = Image.___("hana.jpg")
img.___()
gray = img.convert("___")
gray.save("hana_gray.jpg")

ヒント: PIL / open / show / L(グレースケール)

穴埋め解答
PIL / open / show / L
③ solo — 白紙で書く

pip 確認コマンドと、open→show→convert→save の4行を白紙で書け。

solo 解答例(書いたあと照合)
pip show Pillow\nfrom PIL import Image\nimg=Image.open('x.png')\n...
よくあるバグ
  • パッケージ名を小文字モジュールとして import する誤り / from Pillow import Image(誤り)
  • ファイルパスがカレントと違う
  • draw オブジェクトに save しようとする
採点ポイント
  • pip または import 確認
  • from PIL import Image
  • open / show / convert または save

ドリル⑥ mondai 関数+10回計測

資料準拠: OOL_6月23日 演習(第12回冒頭でも再掲)

問題文 1〜10 の乱数2つの足し算を出す mondai 関数を作り、解答入力できるようにする。 それを 10回繰り返し、かかった時間を計測せよ。
答案型

この問題の答案型(骨格)

import random
import time

def mondai():
    a = random.randint(1, 10)
    b = random.randint(1, 10)
    ...
t0 = time.time()
for i in range(10):
    mondai()
t1 = time.time()
print(t1 - t0)
① worked — 完成コード+解説
import random
import time

def mondai():
    a = random.randint(1, 10)
    b = random.randint(1, 10)
    ans = int(input(f"{a}+{b}= "))
    if ans == a + b:
        print("正解です")
    else:
        print("不正解です")

t0 = time.time()
for _ in range(10):
    mondai()
t1 = time.time()
print("かかった時間:", t1 - t0)

開始・終了を time.time() で挟む。練習問題2は1問だけ+和の表示。演習は10回ループが差。

② faded — 穴埋め(手で埋めてから開く)
import random
import ___
def mondai():
    a = random.randint(1, 10)
    b = random.randint(1, 10)
    ans = int(input(...))
    ...
t0 = time.___()
for _ in range(___):
    mondai()
print(time.time() - t0)

ヒント: time / time / 10

穴埋め解答
time / time / 10
③ solo — 白紙で書く

mondai 定義+計測付き for を手書き。表示文言は「正解です/不正解です」。

solo 解答例(書いたあと照合)
worked と同型
よくあるバグ
  • time.sleep と time.time を混同
  • ループ外で1回だけ計測終了
  • input を int 化せず文字列比較
採点ポイント
  • mondai 関数
  • randint 1〜10
  • 10回ループ
  • time.time 差分

ドリル⑦(L4類題)回転30度

開いた画像を 30 度回転して保存する1行は?(L3 open とは別操作)

ヒント(フェード)

rotate メソッド。

解答・誤答パターン

答え: img.rotate(30).save('out.jpg') など

よくある落とし穴: 角度をラジアンで渡す/show だけして保存しない

ドリル⑧ チェック:コーヒー/お茶/ジュース

資料準拠: OOL_6月30日 練習問題1(宿題)

問題文チェックボタンでコーヒー・お茶・ジュースを選択。ボタン押下で選択商品を画面表示する UI。
答案型

この問題の答案型(骨格)

import tkinter as tk
base = tk.Tk()
b0 = tk.BooleanVar()
b1 = tk.BooleanVar()
b2 = tk.BooleanVar()
# Checkbutton ×3 + Button(command=show) + Label/StringVar
base.mainloop()
① worked — 完成コード+解説
import tkinter as tk

base = tk.Tk()
names = ["コーヒー", "お茶", "ジュース"]
flags = [tk.BooleanVar() for _ in names]
out = tk.StringVar(value="")

for name, fl in zip(names, flags):
    tk.Checkbutton(base, text=name, variable=fl).pack(anchor=tk.W)

def show():
    picked = [n for n, fl in zip(names, flags) if fl.get()]
    out.set(", ".join(picked) if picked else "(未選択)")

tk.Button(base, text="表示", command=show).pack()
tk.Label(base, textvariable=out).pack()
base.mainloop()

BooleanVar.get() が True の名前を集める。練習2は for+辞書で同じUIを短くする(上の for 版がそれ)。

② faded — 穴埋め(手で埋めてから開く)
import tkinter as tk
base = tk.Tk()
bln = tk.___()
tk.Checkbutton(base, text="コーヒー", variable=___).pack()
def show():
    print(bln.___())
tk.Button(base, text="表示", command=show).pack()
base.mainloop()

ヒント: BooleanVar / bln / get

穴埋め解答
BooleanVar / bln / get
③ solo — 白紙で書く

3チェック+表示ボタンをヒントなしで書け(辞書 for 版推奨)。

solo 解答例(書いたあと照合)
worked の for 版
よくあるバグ
  • variable に文字列を直接渡す
  • get せずに表示しようとする
  • Radiobutton を誤用(排他選択になる)
採点ポイント
  • BooleanVar×商品数
  • Checkbutton の variable
  • ボタンで get→表示
  • mainloop

ドリル⑨ ラジオ:A/B/Cランチ+for

資料準拠: OOL_6月30日 演習問題(宿題)

問題文ラジオを Aランチ・Bランチ・Cランチの3つに。同じ処理の繰り返しは for で書く。
答案型

この問題の答案型(骨格)

import tkinter as tk
base = tk.Tk()
v = tk.IntVar(value=0)
lunch = {0: "Aランチ", 1: "Bランチ", 2: "Cランチ"}
for i in range(len(lunch)):
    tk.Radiobutton(base, text=lunch[i], value=i, variable=v).pack()
# 表示ボタンで v.get() → lunch[v.get()]
base.mainloop()
① worked — 完成コード+解説
import tkinter as tk

base = tk.Tk()
v = tk.IntVar(value=0)
lunch = {0: "Aランチ", 1: "Bランチ", 2: "Cランチ"}
for i in range(len(lunch)):
    tk.Radiobutton(
        base, text=lunch[i], value=i, variable=v
    ).pack(anchor=tk.W)

msg = tk.StringVar()

def show():
    msg.set(lunch[v.get()])

tk.Button(base, text="決定", command=show).pack()
tk.Label(base, textvariable=msg).pack()
base.mainloop()

IntVar は選択中の value。text と value を辞書で対応させるのが宿題の意図。

② faded — 穴埋め(手で埋めてから開く)
v = tk.___(value=0)
lunch = {0:"Aランチ", 1:"Bランチ", 2:"Cランチ"}
for i in range(len(lunch)):
    tk.___(base, text=lunch[i], value=i, variable=v).pack()
print(lunch[v.___()])

ヒント: IntVar / Radiobutton / get

穴埋め解答
IntVar / Radiobutton / get
③ solo — 白紙で書く

辞書+for+Radiobutton+決定ボタンを白紙で書け。

solo 解答例(書いたあと照合)
worked と同型
よくあるバグ
  • Checkbutton で作ってしまう
  • Radiobutton ごとに別 IntVar
  • value を付け忘れると選択が壊れる
採点ポイント
  • 共通 IntVar
  • for で3つ生成
  • value と辞書の対応
  • get で表示

ドリル⑩(L4)下から並べる pack

Button を下から並べる。L3 の LEFT とは別。

ヒント(フェード)

side 定数。

解答・誤答パターン

答え: pack(side=tk.BOTTOM)

よくある落とし穴: anchor だけ書いて side を忘れる

ドリル⑪ GameCharacter

資料準拠: OOL_7月7日 練習問題1

問題文 GameCharacter: コンストラクタでジョブとライフ。 info でジョブとライフを表示。 例: 騎士 life=120、魔法使 life=80 のインスタンスを作り info 実行。
答案型

この問題の答案型(骨格)

class GameCharacter:
    def __init__(self, job, life):
        self.job = job
        self.life = life
    def info(self):
        print(self.job, self.life)
① worked — 完成コード+解説
class GameCharacter:
    def __init__(self, job, life):
        self.job = job
        self.life = life
    def info(self):
        print("ジョブ:", self.job, "ライフ:", self.life)

c1 = GameCharacter("騎士", 120)
c2 = GameCharacter("魔法使", 80)
c1.info()
c2.info()

life/job は個体ごと → 必ず self。クラス変数にすると全員共有になる。

② faded — 穴埋め(手で埋めてから開く)
class GameCharacter:
    def __init__(self, job, life):
        ___.job = job
        self.___ = life
    def info(self):
        print(self.job, self.life)
GameCharacter("騎士", ___).info()

ヒント: self / life / 120

穴埋め解答
self / life / 120
③ solo — 白紙で書く

クラス定義+2インスタンス+info を手書き。

solo 解答例(書いたあと照合)
worked と同型
よくあるバグ
  • self 忘れ
  • info に引数を余分に要求
  • クラス変数 life にする
採点ポイント
  • __init__(self, job, life)
  • self 代入
  • info 表示
  • 2インスタンス

ドリル⑫ 攻撃ボタンで相手方向へ move

資料準拠: OOL_7月7日 演習+追加 / 第14回冒頭

問題文 左右キャラそれぞれに「攻撃」ボタン。押した側の画像を相手方向へ移動(move)。 途中まででも提出可、と資料にあるが、答案では move+update まで書けること。
答案型

この問題の答案型(骨格)

# canv: Canvas, tags "left" / "right"
def attack_left():
    for _ in range(10):
        canv.move("left", 10, 0)   # 右へ
        canv.update()

def attack_right():
    for _ in range(10):
        canv.move("right", -10, 0)  # 左へ
        canv.update()

tk.Button(..., command=attack_left)
tk.Button(..., command=attack_right)
① worked — 完成コード+解説
import tkinter as tk

base = tk.Tk()
canv = tk.Canvas(base, width=600, height=400)
canv.pack()
# 画像は PhotoImage + create_image(..., tags="left"/"right") を想定

def attack_left():
    for _ in range(8):
        canv.move("left", 12, 0)
        canv.update()

def attack_right():
    for _ in range(8):
        canv.move("right", -12, 0)
        canv.update()

tk.Button(base, text="左の攻撃", command=attack_left).pack(side=tk.LEFT)
tk.Button(base, text="右の攻撃", command=attack_right).pack(side=tk.RIGHT)
base.mainloop()

move は相対。左→右は +dx、右→左は −dx。update がないと動きが見えない。coords は絶対座標。

② faded — 穴埋め(手で埋めてから開く)
def attack_left():
    for _ in range(8):
        canv.___("left", ___, 0)
        canv.___()
def attack_right():
    canv.move("right", ___, 0)  # 符号に注意

ヒント: move / 正の dx / update / 負の dx

穴埋め解答
move / 12 / update / -12
③ solo — 白紙で書く

左右攻撃関数を白紙で書け。dx の符号理由を1行コメントで。

solo 解答例(書いたあと照合)
worked と同型。コメント例: # 右方向が正
よくあるバグ
  • 左右とも同じ +dx
  • update 忘れ
  • move と coords を混同
  • jpg を PhotoImage に直接渡す
採点ポイント
  • タグ指定
  • 左右で dx 符号が逆
  • update
  • Button の command 結び

ドリル⑬(L4)create_image 座標

幅500×高さ500 Canvas の中央付近に png を置く座標の目安は?(L3 は 400×560 の 200,300)

ヒント(フェード)

中心指定。

解答・誤答パターン

答え: おおよそ (250, 250)

よくある落とし穴: (0,0) に置いて半分欠ける

ドリル⑭ おみくじアプリ骨格

資料準拠: OOL_7月14日 練習問題1

問題文Canvas+画像(または文字)+ボタンでおみくじ結果を切り替えるアプリ。ラベル text 更新または create_text/画像切替。
答案型

この問題の答案型(骨格)

import tkinter as tk
import random
base = tk.Tk()
canv = tk.Canvas(base, width=300, height=400)
canv.pack()
label = tk.Label(base, text="おみくじ")
label.pack()
def draw():
    kekka = random.choice(["大吉", "吉", "凶"])
    label["text"] = kekka   # または label.config(text=kekka)
    canv.update()
tk.Button(base, text="引く", command=draw).pack()
base.mainloop()
① worked — 完成コード+解説
import tkinter as tk
import random

base = tk.Tk()
base.title("おみくじ")
canv = tk.Canvas(base, width=280, height=360, bg="#fff8e7")
canv.pack()
# 背景画像がある場合: PhotoImage + create_image(中心)

result = tk.Label(base, text="?", font=("", 28))
result.pack()

def hikite():
    result["text"] = random.choice(["大吉", "中吉", "小吉", "吉", "凶"])
    canv.update()

tk.Button(base, text="おみくじを引く", command=hikite).pack()
base.mainloop()

GUI の骨格は Tk→Canvas/Label→Button(command)→mainloop。結果更新は Label の text か Canvas の create_text。

② faded — 穴埋め(手で埋めてから開く)
import tkinter as tk
import ___
base = tk.Tk()
result = tk.Label(base, text="?")
def hikite():
    result["text"] = random.___([...])
tk.Button(base, text="引く", command=___).pack()
base.___()

ヒント: random / choice / hikite / mainloop

穴埋め解答
random / choice / hikite / mainloop
③ solo — 白紙で書く

おみくじ最小構成を手書き(import〜mainloop)。結果候補は自分で3つ以上。

solo 解答例(書いたあと照合)
worked と同型で choice リストだけ変更可
よくあるバグ
  • mainloop 忘れ
  • command=hikite() と括弧付きで即実行
  • PhotoImage をローカル変数だけにして消える
採点ポイント
  • Tk と mainloop
  • Button command
  • random で結果変更
  • 表示更新

ドリル⑮ Book / Magazine / Comic

資料準拠: OOL_7月14日 練習問題2(宿題・文言ほぼそのまま)

問題文
  1. Book(name, price) + display
  2. Magazine: 親コンストラクタ呼び出し+keyword, 発行月。display は親を呼んでから追加
  3. Comic: keyword, 巻。同様
  4. m1=月刊釣り名人,1000,釣りスポット,8月号 / c1=名探偵コナン,500,推理もの,10巻
  5. display をポリモーフィズムで同じ関数から実行
答案型

この問題の答案型(骨格)

class Book: ...
class Magazine(Book):
    def __init__(self, name, price, keyword, month):
        super().__init__(name, price)
        ...
    def display(self):
        super().display()
        ...
class Comic(Book): ...
def show(obj):
    obj.display()
① worked — 完成コード+解説
class Book:
    def __init__(self, name, price):
        self.name = name
        self.price = price
    def display(self):
        print(self.name, self.price)

class Magazine(Book):
    def __init__(self, name, price, keyword, month):
        super().__init__(name, price)
        self.keyword = keyword
        self.month = month
    def display(self):
        super().display()
        print(self.keyword, self.month)

class Comic(Book):
    def __init__(self, name, price, keyword, volume):
        super().__init__(name, price)
        self.keyword = keyword
        self.volume = volume
    def display(self):
        super().display()
        print(self.keyword, self.volume)

def show(obj):
    obj.display()

m1 = Magazine("月刊釣り名人", 1000, "釣りスポット", "8月号")
c1 = Comic("名探偵コナン", 500, "推理もの", "10巻")
show(m1)
show(c1)

super 二箇所(init と display)が減点ポイント。呼び出しは show(obj) 一種類。

② faded — 穴埋め(手で埋めてから開く)
class Magazine(Book):
    def __init__(self, name, price, keyword, month):
        ___.__init__(name, price)
        self.keyword = keyword
        self.month = month
    def display(self):
        super().___()
        print(self.keyword, self.month)
def show(obj):
    obj.___()

ヒント: super / display / display

穴埋め解答
super / display / display
③ solo — 白紙で書く

宿題の引数どおり m1/c1 まで手書き。Magazine のスペルは資料どおりでも Magazine 正規でも可(試験は指示に合わせる)。

solo 解答例(書いたあと照合)
worked と同型
よくあるバグ
  • super 省略して親フィールドを再invent
  • display で親を呼ばず子だけ表示
  • show をクラスごとに2つ作る
採点ポイント
  • 継承
  • super().__init__
  • super().display()
  • 共通 show
  • 指定インスタンス引数

ドリル⑯(L4類題)Novel+author

Book を継承し author を追加した Novel を設計(Magazine の month とは別フィールド)。

ヒント(フェード)

super().__init__(name, price) のあと self.author。

解答・誤答パターン

答え: class Novel(Book): def __init__(..., author): super().__init__(name,price); self.author=author

よくある落とし穴: 親フィールドを再invent して super 省略

ドリル⑰(L4 solo)用語

親メソッドを子の同名で置き換える用語は?

ヒント(フェード)

オーバーロードではない。

解答・誤答パターン

答え: オーバーライド

よくある落とし穴: オーバーロードと書く

ドリル⑱(L4)self の呼び出し

メソッド第1引数 self を、呼び出し側で渡す必要があるか?

ヒント(フェード)

中間土台。

解答・誤答パターン

答え: 呼ぶ側は渡さない(インタプリタがインスタンスを渡す)

よくある落とし穴: d.bark(d) のように自分で渡す

用語一覧(想起用)

初出の本説明は入門カード。ここは索引。主役はコーディングドリル。

用語一文手がかり
スコープ変数が有効に使える範囲ローカル vs グローバル
ローカル変数関数ブロック内だけで生きる変数関数を抜けると消える
グローバル変数ファイル先頭レベルで定義される変数ファイル全体で参照可
インスタンス変数self. で持つ、個体ごとのデータself.job
クラス変数クラス全体で共有するデータクラス名.変数
ポリモーフィズム同じ操作名で型ごとに違う処理を呼び出せることobj.cry()
オーバーライド親の同名メソッドを子で上書きすることDog.cry
標準ライブラリPython同梱で import して使う道具箱random, math, calendar
外部ライブラリpip 等で追加インストールする道具箱Pillow
モジュール拡張子 .py の道具ファイルimport math
パッケージ複数モジュールをまとめたディレクトリfrom tkinter import …
Pillow / PIL画像を開く・変形する外部ライブラリfrom PIL import Image
tkinter標準の GUI ライブラリTk, Button, Label
ウィジェット画面に置く部品(Button 等)pack で配置
packウィジェットを上下左右に並べる配置法side=LEFT
StringVarEntry 等と連動する文字列ウィジェット変数moji.get()
BooleanVarチェックの有無を持つ真偽ウィジェット変数bln.set(True)
IntVarラジオの value を持つ整数ウィジェット変数int_v.get()
Canvas図形・画像を描く描画面create_image
PhotoImagetkinter で PNG 等を扱う画像オブジェクトjpg 非対応
move / coordsCanvas 上の相対移動 / 絶対座標設定攻撃アニメ
update描画をその時点で画面に反映する移動の直後に呼ぶ
継承親クラスの機能を子が引き継ぐことclass Comic(Book)
super()親クラスのメソッドを子から呼ぶ仕組みsuper().__init__

確認クイズ

自信度つき。高自信で誤答したトピックは間違いノートへ。コード手書きは演習ドリル優先。

間違いノート

まだなし。診断の高自信誤答が溜まる。

    Layer0 — 1行地図+手書き順

    • スコープ: 作った場所=見える範囲 → L1 / L3
    • ポリモーフィズム: Animal / Circle・Square → ドリル② /
    • ライブラリ: dice+Pillow+mondai → / /
    • tkinter: Check / Radio → /
    • Canvas: GameCharacter・攻撃 → /
    • 継承総復習: おみくじ・Book → /
    • 中間土台: 中間サイト
    試験直前30分 答案型チートを暗唱 → 弱点ドリルを solo 1本 → 暗箱用語は入門カードだけ。
    初見ドリル強制なし。弱点だけ戻る。

    講義回・宿題 parity

    ID内容判定メモ
    L1第1回講義PDFout-of-scope資料未入手。中間サイトのゼロ起点で代替可
    L2-7-mid第2–7回(中間範囲)covered本線外。入門要約+https://ool-midterm.pages.dev/ へ誘導
    L8第8回(6/9・中間試験日の可能性大)out-of-scope講義PDFなし。中間試験日と推定
    L9第9回 スコープ・ポリモーフィズム・標準ライブラリcoveredcore-scope
    L10第10回 Pillow・外部ライブラリcoveredcore-lib
    L11第11回out-of-scope休講想定のため out-of-scope / 欠番
    L12第12回 tkinter 基礎coveredcore-tkinter
    L13第13回 Canvas・GameCharactercoveredcore-canvas
    L13-add7月7日追加(攻撃動作)coveredcore-canvas
    L14第14回 ゲーム復習・おみくじ・Book継承coveredcore-book
    hw-poly宿題 Animal/Dog/Snake ポリモーフィズムcovereddrill-animal
    hw-circle-square宿題 CircleArea/SquareArea+cal_areacovereddrill-circle-square
    hw-dice宿題 サイコロ2個+math.fabscovereddrill-dice
    hw-pillow宿題 Pillow 画像操作covereddrill-pillow
    hw-mondai宿題 mondai関数10回計測covereddrill-mondai
    hw-tk宿題 tkinter チェック/ラジオ・for辞書covereddrill-check
    hw-canvas宿題 Canvas攻撃ボタンcovereddrill-attack
    hw-book宿題 Book/Magazine/Comiccovereddrill-book
    hw-omikuji宿題 おみくじアプリcovereddrill-omikuji
    thin 禁止 宿題同型(Circle/Square、Animal、dice、Pillow、mondai、チェックUI、攻撃move、Book系)は 本編 L3+コーディングドリルに手数あり → covered。 第1/8/11回は out-of-scope(欠番・休講想定)。

    人手ゲート

    • 入門 L1 カードに term-* マーカあり
    • 各本線トピックに L2+L3(途中手順フル)
    • コーディングドリル: 問題文→答案型→worked→faded→solo
    • L4 は別数値・別文言(surface 分離)
    • ASCII 暗箱 pre.term-image なし
    • 中間 URL は既存 midterm を参照(期末は別 slug)