スコープ
ローカル/グローバル/self
STUDY GUIDE · オブジェクト指向型言語
期末試験対策 · 第9–10・12–14回本線
入門で用語を固めてから、演習と同型コードを手で書くドリルへ。中間(第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 を増やさないため、期末は後半本線に集中する。
本編のコードトレースに入る前に、試験用語をここで読み切る。薄い要約禁止。各カードに定義・なぜ・イメージ・仕組み・答案一言を揃えた。
なぜ今学ぶか: 期末以降のクラス・関数コードでは、見た目同じ変数名がローカル/グローバル/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文で書く。
なぜ: 宿題の関数・メソッドで「外から見えない」「中から見える」を説明できる必要がある。
ローカルは関数ブロック内だけの変数。グローバルはファイルのトップレベルで定義された変数。
別名: local / global。
def f(): の中でだけ定義した area
area は消える(外側から参照するとエラー)
仕組み: ローカルはブロックを出ると寿命が尽きたとみなされる。グローバルはファイル実行中ずっと名前空間に残る。
| 種類 | 定義場所 | 外から |
|---|---|---|
| ローカル | 関数内 | 不可 |
| グローバル | トップレベル | 可 |
クラス内メソッドのローカル area と self.area(インスタンス変数)を混同しない。
試験答え方: 表で「定義場所/外から使えるか」を対比して書く。
なぜ: 第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.変数=個体ごと/クラス.変数=共有」と対で書く。
なぜ: 期末宿題の Animal.cry / Book.display の核心。ここが弱いと「ただの別関数呼び出し」で終わる。
同じ操作の名前で、相手の型ごとに違う処理を呼び出せること。呼び出し側を型ごとに書き換えなくてよい。
別名: 多態性。講義では「同じボタンで車は発進するが中身は違う」たとえ。
hero.speak() と enemy.speak() を別々に書く
def intro(obj): return obj.speak()
仕組み: 各クラスに同名メソッドを用意(必要ならオーバーライド)。呼び手は obj.メソッド() だけ書く。実行時に実体の型の実装が選ばれる。
車の発進ボタンはどれも「Aボタン」。中身はゆっくり発進でも急加速でも、運転手の操作は同じ。
「継承が必須」ではない。異なるクラスに同名メソッドがあればポリモーフィズムの考え方は使える。ただし講義演習は継承+オーバーライドが多い。
試験答え方: 「呼び出し側を変えず、同じメソッド名で型ごとの処理を実行できること」+短いコード例。
なぜ: Dog.cry が「わんわん」になるのはオーバーライド。ポリモーフィズムの実装手段。
親クラスで定義したメソッドを、子クラスで同名メソッドとして上書きすること。
別名: 上書き。オーバーロード(引数違いの多重定義)とは別物。
親 Animal.cry → 「鳴く」
Dog.cry → 「わんわん」
仕組み: 子に同名メソッドを書くと、そのインスタンスでは親の実装より子が優先される。親の続きを使いたいときは super()。
オーバーロードと混同しない。Python は基本的に後から定義した同名が上書きになる。
試験答え方: 「親の同名メソッドを子で上書きすること」と定義し、例を1つ添える。
なぜ: random / math / calendar / datetime / tkinter が期末本線。import の書き方がそのまま点数になる。
標準ライブラリは Python 同梱の道具箱。モジュールは .py の道具ファイル。パッケージはモジュールをまとめたフォルダ。
別名: 標準ライブラリ ≠ 組み込み関数(abs 等は import 不要)。
道具箱(ライブラリ)
モジュール=個別の道具、パッケージ=セット売り
仕組み: import 名前 で読み込む。as で別名、from … import … で一部だけ取り込む。
import random
from math import sqrt, pi
import calendar as calrandom は標準なのに pip が要ると勘違いしがち。逆に Pillow は外部で pip が要る。
試験答え方: 「標準=同梱だが import 必要/組み込み=import 不要」を対比。
なぜ: 第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」。
なぜ: 第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」の流れを書く。
なぜ: 入力欄の文字やチェック状態を get/set で読み書きするのが宿題の型。
Entry・チェック・ラジオなどと連動して、画面の入力状態を Python 側で持つ専用の変数クラス。
別名: コントロール変数。textvariable / variable オプションで結ぶ。
ユーザーが Entry に文字を打つ
moji.get() で文字列を取得
仕組み: StringVar=文字列、BooleanVar=真偽、IntVar=整数(ラジオの value)。set で初期値、get で取得。
普通の str 変数を textvariable に渡しても連動しない。必ず *Var インスタンス。
試験答え方: 用途ごとにどの Var かを選び、「variable=…」で結ぶと答える。
なぜ: 第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 注意)」。
なぜ: 攻撃ボタン課題の核心。どちらを使うかで答えが変わる。
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 を挟む」。
なぜ: 第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__」。
なぜ: 期末サイトは本線を後半に絞る。復習は中間サイトを正本にする。
期末は中間のクラス/self/継承の上に、スコープ・ライブラリ・GUI が載る。土台が揺れると後半が全部崩れる。
別名: 第2–7回。詳細は中間サイトへ。
クラス・インスタンス・self が曖昧
期末の GameCharacter / Book が読める
仕組み: 設計図=クラス、実体=インスタンス、メソッド第1引数=self(呼ぶ側は渡さない)、子(親)=継承。
試験答え方: 中間用語は中間サイトの定義で答える。期末答案では後半トピックを優先。
記号に入る前に: 「どこで作ったか」だけ見れば種類が決まる。self の有無が最大の分岐。
| 種類 | 書き方 | 読み下し |
|---|---|---|
| ローカル | area = …(メソッド内・selfなし) | この関数の一時メモ |
| グローバル | ファイル先頭の v = … | ファイル全体の共有メモ |
| インスタンス | self.r = r | この個体の属性 |
| クラス | クラス直下 x = 0 | クラス全員の共有属性 |
アクセス: 外からインスタンス変数は obj.r。クラス変数は Circle.x または(読取なら)self.x。
関数ブロック内で代入された名前は、その関数のローカルになる。関数外の同名グローバルとは別物。
v = 10 # global
def printer():
v = 20 # local(関数内だけ)
print(v)
class Circle:
x = 0 # クラス変数
def __init__(self, r):
self.r = r # インスタンス変数
def area(self):
area = 3.14*self.r**2 # ローカル(外から見えない)
return area
与件: 次のコードがある。
v = 10
def printer():
v = 20
print(v)
printer()
print(v)
求めよ: (1) printer() 実行時に表示される値 (2) 直後の print(v) の値。理由も書け。
なぜ今この計算か: 同名でもスコープが違えば別変数。試験では「表示値+理由」セットが答案になる。
v=10 → グローバル v が 10。printer() に入る。関数内 v=20 はローカル v を作る(グローバルはまだ 10)。print(v) はローカルを見る → 20。print(v) はグローバル → 10。答案文: printer 内の v はローカルなので 20 が表示され、外側の print はグローバルの 10 を表示する。
部分点: 表示値だけ合って理由なし → 半分。ローカル/グローバルの語が出れば加点。
考察: 考察: 数値 20 と 10 の差は「代入した場所」だけを見れば説明できる。restart なしで続けて実行すると状態が汚れやすい点にも注意。
記号に入る前に: 運転手は「発進ボタン」だけ知っていればよい。車種ごとのエンジン制御は車側が持つ。
def self_introduction(obj):
return obj.speak() # 呼び出し側は型を気にしない
各クラスに speak(または cry)があれば、同じ関数で扱える。
class Animal:
def cry(self):
return "鳴く"
class Dog(Animal):
def cry(self): # オーバーライド
return "わんわん"
与件(第9回演習):
1. 親 Animal の cry は "鳴く" を返す。
2. 子 Dog は "わんわん"、子 Snake は "シャー"。
3. 各子の cry をポリモーフィズムの考えで実行せよ。
求めよ: 完成コードと、共通関数から呼ぶ実行例。
なぜ今この手順か: 宿題同型。定義→オーバーライド→共通呼び出しの3段が答案フォーマット。
class Dog(Animal)、オーバーライド、共通関数 def play(obj): return obj.cry()class Animal:\n def cry(self):\n return "鳴く"
class Dog(Animal):\n def cry(self):\n return "わんわん"
return "シャー"。def play(obj):\n return obj.cry()
print(play(Dog())); print(play(Snake())) → わんわん / シャー。答案文: 各子で 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()))
与件: Animal().cry() は「鳴く」、Dog().cry() は「わんわん」。求めよ: Dog 側で何をしたか(用語+1行コードの意味)。
なぜ今この問か: 用語「オーバーライド」を答案に書けるか確認する。
答案文: Dog は親の cry を同名メソッドで上書き(オーバーライド)し、「わんわん」を返す。
部分点: 「継承した」だけ → 不十分。上書きに言及すること。
考察: 考察: 継承だけでは親の「鳴く」のまま。出力が変わった瞬間がオーバーライド。
記号に入る前に: 標準ライブラリは「最初からカバンに入っているが、使うには取り出す(import)」。
| 書き方 | 意味 |
|---|---|
import random | モジュールごと。以降 random.randint |
import calendar as cal | 別名 |
from math import sqrt, pi | 一部だけ。以降 sqrt(…) |
組み込み abs は import 不要。math.fabs は import 必要。
pip install Pillowfrom PIL import Imageimg = Image.open(path) → 変形・保存与件(第9回演習2): 1〜6の乱数を2つ(di1, di2)。一致なら「同じ数」、違えば差の絶対値を表示。絶対値は math を import して使う。求めよ: 完成手順と表示分岐。
なぜ今この手順か: random と math を同時に使う宿題同型。
import random と import math。di1 = random.randint(1, 6)、di2 = random.randint(1, 6)。if di1 == di2: → print「同じ数」。print(math.fabs(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))
与件: 外部ライブラリ Pillow を使い、ファイル sample.png を開いてサイズを表示したい。求めよ: インストール確認から表示までの手順。
なぜ今この手順か: 外部ライブラリは「入れる→import→使う」の3点が採点ポイント。
pip install Pillow(未導入時)。pip show Pillow または from PIL import Image が通るか確認。from PIL import Imageimg = Image.open('sample.png')print(img.size) で (幅, 高さ) を確認。答案文: Pillow を導入し PIL.Image で sample.png を開いた。
部分点: パッケージ名を小文字で import した → 誤り(正: from PIL import Image)。
考察: 考察: パッケージ名 Pillow と import 名 PIL のズレはよく出る引っかけ。
記号に入る前に: 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 で方角寄せ。
| クラス | 用途 | 典型 |
|---|---|---|
| StringVar | Entry / Label 文字 | textvariable=moji |
| BooleanVar | Checkbutton | variable=bln / set(True) |
| IntVar | Radiobutton の value | variable=int_v |
与件: Tk ウィンドウに Button を2つ置き、左から並べる。クリックで print('ok')。求めよ: 最小コード。
なぜ今この手順か: pack(side=LEFT) と command の結びが基本点。
import tkinter as tkbase = tk.Tk()pack(side=tk.LEFT)。base.mainloop()答案文: Tk 上に Button を LEFT で pack し、command で ok を結んだ。
部分点: mainloop 忘れ → 画面が一瞬で消える/出ない。
考察: 考察: side を指定しないと TOP(縦積み)になる。見た目で採点されやすい。
与件(第12回練習1): コーヒー・お茶・ジュースをチェック可能にし、ボタンで選択商品を画面表示。求めよ: BooleanVar×3 と表示更新の手順。
なぜ今この手順か: 宿題同型。Var・Checkbutton・Button の連携が本体。
答案文: 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()
記号に入る前に: 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 は講義で非対応と注意。
canv.move("rect_1", 10, 50) # 相対
canv.update()
canv.coords("rect_1", 200, 300) # 絶対(中心)
与件: 幅400×高さ560の Canvas。350×410 の png を見切れにくく置きたい。求めよ: create_image の座標の選び方。
なぜ今この計算か: 中心指定を間違えると半分欠ける。
答案文: Canvas 中央付近を中心座標にして png を配置した。
部分点: (0,0) 配置のまま → 大きく欠ける。
考察: 考察: 画像サイズが Canvas より大きいときは縮小か Canvas 拡大が先。
与件(第13回演習): 左右キャラに攻撃ボタン。押した側の画像を相手方向へ move。求めよ: 左側ボタン用の相対移動の考え方。
なぜ今この手順か: 追加資料の攻撃描画と同型。左右で dx の符号が逆。
canv.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()
記号に入る前に: 共通(タイトル・値段)は親、差分(月号・巻)は子。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)
与件(第14回練習2): - Magazine: 月刊釣り名人, 1000, 釣りスポット, 8月号 → m1 - Comic: 名探偵コナン, 500, 推理もの, 10巻 → c1 最後に display をポリモーフィズムで同じ関数から実行。求めよ: クラス骨子と呼び出し。
なぜ今この手順か: 期末直前の総合。継承・super・ポリモーフィズムが1問に圧縮されている。
答案文: 親 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)は下の各ドリルと本編 L3。②フェード(faded)は穴埋め。③自力(solo)は白紙でノートに書く。L3 と同数値・同文言のコピペ禁止(L4 は別 surface)。
期末は演習と同じ/ほぼ同じコードを白紙から書ける力が本命。 入門用語は土台。主役は下のドリル(問題文→答案型→worked→faded→solo)。
| 回 | テーマ | ドリル |
|---|---|---|
| 第9 | スコープ・面積ポリ・Animal・サイコロ | Circle/Square · Animal · dice |
| 第10 | Pillow・time・足し算タイマー | Pillow · mondai計測 |
| 第12 | チェック/ラジオ+for | 飲み物Check · ランチRadio |
| 第13+追加 | GameCharacter・攻撃move | GameCharacter · 攻撃ボタン |
| 第14 | おみくじ・Book継承 | おみくじ · Book系 |
資料準拠: OOL_6月16日 練習問題1(宿題)
CircleArea: コンストラクタ引数 r。面積 cc を返す area。SquareArea: 引数 a。面積 ss を返す area。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()
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 は宿題表記に合わせた。
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ノートにクラス2つ+cal_area を白紙で書け。数値は r=5, a=4 で動かしたつもりで答えも書け。
# 例: cal_area(CircleArea(5)) → 78.5
# cal_area(SquareArea(4)) → 16
# (実装は worked と同型。数値だけ変える)資料準拠: OOL_6月16日 演習問題1(宿題)※文言ほぼそのまま
Animal の cry は "鳴く" を返す。Dog は "わんわん"。Snake は "シャー"。cry をポリモーフィズムの考えに基づいたコードで実行。この問題の答案型(骨格)
class Animal:
def cry(self): ...
class Dog(Animal):
def cry(self): ...
class Snake(Animal):
def cry(self): ...
def play(obj):
return obj.cry()
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) 一種類。出力が分かれること自体が答案の証拠。
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ヒントなしで3クラス+共通関数を手書き。実行結果3行も予想して書け。
わんわん\nシャー\n鳴く資料準拠: OOL_6月16日 演習問題2(宿題)
この問題の答案型(骨格)
import random
import math
di1 = random.randint(1, 6)
di2 = random.randint(1, 6)
if di1 == di2:
print("同じ数")
else:
print(math.fabs(di1 - di2))
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 を返す。
import ___
import math
di1 = random.randint(___, ___)
di2 = random.randint(1, 6)
if di1 ___ di2:
print("同じ数")
else:
print(math.___(di1 - di2))
ヒント: モジュール名/範囲/比較演算子/絶対値関数名。
random / 1 / 6 / == / fabsimport から if/else までノートに書け。範囲は宿題どおり 1〜6。
worked と同型。実行結果は乱数依存。グローバル n=3。関数内 n=9 して print。外側で print。表示は?(L3 の 10/20 とは別)
関数内代入=ローカル。外側はグローバルのまま。
答え: 関数内 9、外側 3
よくある落とし穴: 両方 9(グローバル上書きと誤解)
資料準拠: OOL_6月23日 サンプル+導入確認
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")
# 事前: 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 オブジェクト側。
from ___ import Image
img = Image.___("hana.jpg")
img.___()
gray = img.convert("___")
gray.save("hana_gray.jpg")
ヒント: PIL / open / show / L(グレースケール)
PIL / open / show / Lpip 確認コマンドと、open→show→convert→save の4行を白紙で書け。
pip show Pillow\nfrom PIL import Image\nimg=Image.open('x.png')\n...資料準拠: OOL_6月23日 演習(第12回冒頭でも再掲)
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)
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回ループが差。
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 / 10mondai 定義+計測付き for を手書き。表示文言は「正解です/不正解です」。
worked と同型開いた画像を 30 度回転して保存する1行は?(L3 open とは別操作)
rotate メソッド。
答え: img.rotate(30).save('out.jpg') など
よくある落とし穴: 角度をラジアンで渡す/show だけして保存しない
資料準拠: OOL_6月30日 練習問題1(宿題)
この問題の答案型(骨格)
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()
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 版がそれ)。
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 / get3チェック+表示ボタンをヒントなしで書け(辞書 for 版推奨)。
worked の for 版資料準拠: OOL_6月30日 演習問題(宿題)
この問題の答案型(骨格)
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()
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 を辞書で対応させるのが宿題の意図。
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辞書+for+Radiobutton+決定ボタンを白紙で書け。
worked と同型Button を下から並べる。L3 の LEFT とは別。
side 定数。
答え: pack(side=tk.BOTTOM)
よくある落とし穴: anchor だけ書いて side を忘れる
資料準拠: 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)
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。クラス変数にすると全員共有になる。
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クラス定義+2インスタンス+info を手書き。
worked と同型資料準拠: OOL_7月7日 演習+追加 / 第14回冒頭
この問題の答案型(骨格)
# 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)
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 は絶対座標。
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左右攻撃関数を白紙で書け。dx の符号理由を1行コメントで。
worked と同型。コメント例: # 右方向が正幅500×高さ500 Canvas の中央付近に png を置く座標の目安は?(L3 は 400×560 の 200,300)
中心指定。
答え: おおよそ (250, 250)
よくある落とし穴: (0,0) に置いて半分欠ける
資料準拠: OOL_7月14日 練習問題1
この問題の答案型(骨格)
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()
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。
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おみくじ最小構成を手書き(import〜mainloop)。結果候補は自分で3つ以上。
worked と同型で choice リストだけ変更可資料準拠: OOL_7月14日 練習問題2(宿題・文言ほぼそのまま)
この問題の答案型(骨格)
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()
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) 一種類。
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宿題の引数どおり m1/c1 まで手書き。Magazine のスペルは資料どおりでも Magazine 正規でも可(試験は指示に合わせる)。
worked と同型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 省略
親メソッドを子の同名で置き換える用語は?
オーバーロードではない。
答え: オーバーライド
よくある落とし穴: オーバーロードと書く
メソッド第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 |
| StringVar | Entry 等と連動する文字列ウィジェット変数 | moji.get() |
| BooleanVar | チェックの有無を持つ真偽ウィジェット変数 | bln.set(True) |
| IntVar | ラジオの value を持つ整数ウィジェット変数 | int_v.get() |
| Canvas | 図形・画像を描く描画面 | create_image |
| PhotoImage | tkinter で PNG 等を扱う画像オブジェクト | jpg 非対応 |
| move / coords | Canvas 上の相対移動 / 絶対座標設定 | 攻撃アニメ |
| update | 描画をその時点で画面に反映する | 移動の直後に呼ぶ |
| 継承 | 親クラスの機能を子が引き継ぐこと | class Comic(Book) |
| super() | 親クラスのメソッドを子から呼ぶ仕組み | super().__init__ |
自信度つき。高自信で誤答したトピックは間違いノートへ。コード手書きは演習ドリル優先。
まだなし。診断の高自信誤答が溜まる。
| ID | 内容 | 判定 | メモ |
|---|---|---|---|
| L1 | 第1回講義PDF | out-of-scope | 資料未入手。中間サイトのゼロ起点で代替可 |
| L2-7-mid | 第2–7回(中間範囲) | covered | 本線外。入門要約+https://ool-midterm.pages.dev/ へ誘導 |
| L8 | 第8回(6/9・中間試験日の可能性大) | out-of-scope | 講義PDFなし。中間試験日と推定 |
| L9 | 第9回 スコープ・ポリモーフィズム・標準ライブラリ | covered | core-scope |
| L10 | 第10回 Pillow・外部ライブラリ | covered | core-lib |
| L11 | 第11回 | out-of-scope | 休講想定のため out-of-scope / 欠番 |
| L12 | 第12回 tkinter 基礎 | covered | core-tkinter |
| L13 | 第13回 Canvas・GameCharacter | covered | core-canvas |
| L13-add | 7月7日追加(攻撃動作) | covered | core-canvas |
| L14 | 第14回 ゲーム復習・おみくじ・Book継承 | covered | core-book |
| hw-poly | 宿題 Animal/Dog/Snake ポリモーフィズム | covered | drill-animal |
| hw-circle-square | 宿題 CircleArea/SquareArea+cal_area | covered | drill-circle-square |
| hw-dice | 宿題 サイコロ2個+math.fabs | covered | drill-dice |
| hw-pillow | 宿題 Pillow 画像操作 | covered | drill-pillow |
| hw-mondai | 宿題 mondai関数10回計測 | covered | drill-mondai |
| hw-tk | 宿題 tkinter チェック/ラジオ・for辞書 | covered | drill-check |
| hw-canvas | 宿題 Canvas攻撃ボタン | covered | drill-attack |
| hw-book | 宿題 Book/Magazine/Comic | covered | drill-book |
| hw-omikuji | 宿題 おみくじアプリ | covered | drill-omikuji |