11日目のゴールとテーマ
11日目のテーマは「クラスとオブジェクトで“自分だけの型”を作る」です。
ここまで、辞書とリストを組み合わせて、かなり複雑なデータも扱えるようになりました。
でも、そろそろこう感じていませんか?
「毎回 {"name": ..., "deadline": ...} って書くの、ちょっとゴチャつく」
「タスクって、もっと“タスクらしいまとまり”として扱えないかな」
今日はここに一歩踏み込んで、
クラス(class)とオブジェクト(インスタンス)のイメージ__init__ で「自分だけの型の“初期化”」を作る
メソッドで「その型専用の関数」を持たせる
タスク管理アプリの「タスク」をクラス化してみる
ここまでを狙います。
クラスとオブジェクトをイメージでつかむ
「設計図」と「そこから作られた実物」
まずは言葉のイメージから整えます。
クラス(class)は「設計図」です。
オブジェクト(インスタンス)は「その設計図から作られた実物」です。
例えば、「タスク」という概念を考えてみます。
タスクには、名前がある
締切がある
「あと何日か」を計算したい
「期限切れかどうか」を知りたい
こういう「タスクというものの性質」をまとめた“設計図”がクラスです。
そこから実際に「レポートを書く」「買い物に行く」といった具体的なタスクを作ったものが、オブジェクト(インスタンス)です。
辞書は「その場その場で自由に作るメモ」
クラスは「ちゃんと決めたフォーマットを持つ型」
こんなイメージを持っておくと、しっくり来やすいです。
いちばん小さなクラスを書いてみる
class と __init__ の基本形
まずは、超シンプルなクラスから始めます。
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
Pythonこれが「Person という型の設計図」です。
ここで出てきたポイントを丁寧に見ていきます。
class Person:
これが「Person というクラスを定義します」という宣言です。
クラス名は、慣習的に先頭を大文字にします。
def __init__(self, name, age):
これが「コンストラクタ」と呼ばれる特別なメソッドです。
オブジェクトが作られるときに、自動的に呼ばれます。__init__ は「イニシャライズ(初期化)」の意味です。
self.name = nameself.age = age
ここで、「このオブジェクトが持つ名前」と「年齢」をセットしています。self は「今まさに作っている(または操作している)このオブジェクト自身」を指します。
このクラスからオブジェクトを作るには、こう書きます。
person1 = Person("太郎", 20)
person2 = Person("花子", 18)
print(person1.name, person1.age)
print(person2.name, person2.age)
Python実行結果はこうなります。
太郎 20
花子 18
ここでの超重要ポイントは、
Person("太郎", 20) と書いた瞬間に、
内部で __init__(self, "太郎", 20) が呼ばれている
ということです。
self には「今作っている person1(や person2)」が自動で入ります。
だから、self.name = name と書くと、
「この人の name に ‘太郎’ を入れる」という意味になります。
メソッドで「その型専用の動き」を持たせる
関数との違いは「self を受け取るかどうか」
クラスの中には、__init__ 以外にも関数(メソッド)を書くことができます。
例えば、Person に「自己紹介する」メソッドを持たせてみましょう。
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def introduce(self):
print("私は" + self.name + "です。年齢は" + str(self.age) + "歳です。")
Python使う側はこうなります。
person = Person("太郎", 20)
person.introduce()
Python実行結果はこうです。
私は太郎です。年齢は20歳です。
ここでのポイントは、
クラスの中の関数は、第一引数に必ず self を取る
呼び出すときは person.introduce() のように書き、self は自動で渡される
ということです。
外側に書く普通の関数は、
def introduce(person):
...
Pythonのように、「誰についての処理か」を引数で受け取ります。
クラスのメソッドは、「自分自身(self)」を暗黙に持っているので、self.name や self.age に直接アクセスできます。
「データ(name, age)と、そのデータに関する処理(introduce)をひとまとめにしたもの」
これがクラスの強みです。
タスクをクラスとして定義してみる
辞書から「Task クラス」へ
ここからが今日の本番です。
これまでタスクは、こんな辞書で表現していました。
task = {"name": "レポートを書く", "deadline": datetime.date(2026, 4, 10)}
Pythonこれをクラスにしてみます。
import datetime
class Task:
def __init__(self, name, deadline):
self.name = name
self.deadline = deadline
def remaining_days(self):
today = datetime.date.today()
diff = self.deadline - today
return diff.days
def status_text(self):
days = self.remaining_days()
deadline_text = self.deadline.strftime("%Y/%m/%d")
if days > 0:
return "締切: " + deadline_text + "(あと " + str(days) + " 日)"
elif days == 0:
return "締切: " + deadline_text + "(今日が締切!)"
else:
return "締切: " + deadline_text + "(期限切れ: " + str(-days) + " 日過ぎ)"
Pythonこの Task クラスの中身を、じっくり分解します。
__init__(self, name, deadline)
タスクを作るときに、「名前」と「締切日」を受け取って、
それを self.name と self.deadline に保存しています。
remaining_days(self)
このメソッドは、「締切まであと何日か」を計算して返します。
中で self.deadline を使っているのがポイントです。
どのタスクかによって締切が違うので、「自分自身の締切」を使っています。
status_text(self)
このメソッドは、「締切の状態を表す文字列」を返します。
中で remaining_days() を呼んでいるのもポイントです。
同じクラスの中のメソッド同士は、self.メソッド名() で呼び合えます。
この Task クラスを使うと、こう書けます。
task = Task("レポートを書く", datetime.date(2026, 4, 10))
print(task.name)
print(task.deadline)
print(task.remaining_days())
print(task.status_text())
Python辞書のときと比べて、
task["name"] ではなく task.nametask["deadline"] ではなく task.deadline
と書けるようになり、
「タスクらしさ」がコードににじみ出てきます。
タスクのリストを「Task オブジェクトのリスト」に変える
使い方は辞書のリストとほぼ同じ
Task クラスができたら、あとは「辞書の代わりに Task を使う」だけです。
これまでのタスクリストはこうでした。
tasks = [
{"name": "レポートを書く", "deadline": datetime.date(2026, 4, 10)},
{"name": "買い物に行く", "deadline": datetime.date(2026, 3, 30)}
]
Pythonこれをこう書き換えます。
tasks = [
Task("レポートを書く", datetime.date(2026, 4, 10)),
Task("買い物に行く", datetime.date(2026, 3, 30))
]
Python一覧表示も、こう変わります。
def print_tasks(tasks):
print("=== タスク一覧 ===")
if len(tasks) == 0:
print("タスクは登録されていません。")
return
for i, task in enumerate(tasks, start=1):
print(str(i) + ". " + task.name + " → " + task.status_text())
Pythonここでの重要ポイントは、
「辞書のときに task["name"] や task["deadline"] と書いていた部分が、task.name や task.status_text() に変わっているだけ」
ということです。
内部表現が辞書からクラスに変わっても、
「タスクのリストを for で回す」という構造は同じです。
だから、クラスを導入しても、これまでの知識はそのまま活きます。
ファイル保存・読み込みを Task クラス対応にする
「外に出すときは文字列」「中に戻すときは Task」
7日目・10日目で作った「ファイル保存・読み込み」を、Task クラス対応にしてみます。
保存側はこうです。
def save_tasks_to_file(tasks, filename):
with open(filename, "w", encoding="utf-8") as file:
for task in tasks:
line = task.name + "," + task.deadline.isoformat() + "\n"
file.write(line)
print("タスクをファイルに保存しました。")
Python読み込み側はこうです。
def load_tasks_from_file(filename):
tasks = []
try:
with open(filename, "r", encoding="utf-8") as file:
for line in file:
line = line.strip()
if line == "":
continue
parts = line.split(",")
if len(parts) != 2:
continue
name = parts[0]
date_text = parts[1]
deadline = parse_date(date_text)
if deadline is None:
continue
task = Task(name, deadline)
tasks.append(task)
print("タスクをファイルから読み込みました。")
except FileNotFoundError:
print("ファイルが見つかりませんでした。新しいタスク一覧を作ります。")
tasks = []
return tasks
Pythonここでのポイントは、
ファイルに書くときは、「Task を文字列に変換している」
ファイルから読むときは、「文字列から Task を作り直している」
ということです。
クラスを使っていても、「ファイルに書けるのは文字列だけ」というルールは変わりません。
だから、
Task(オブジェクト) → 文字列(保存用)
文字列 → Task(オブジェクト)
という変換を、自分で決めて書いています。
11日目のミニアプリ:Task クラス版タスク管理
10日目のアプリを「クラス対応」にする
ここまでの内容をまとめて、
10日目のタスク管理アプリを「Task クラス版」にしたイメージを示します。
全体像はこういう構成になります。
Task クラス(name, deadline, remaining_days, status_text)
parse_date 関数
add_task 関数(Task を作ってリストに追加)
print_tasks 関数(Task のメソッドを使って表示)
save_tasks_to_file / load_tasks_from_file 関数
print_menu / input_menu_number / main
コードは長くなるので、ここでは要所だけ押さえますが、
大事なのは「辞書を Task に置き換えるだけで、構造はほぼそのまま」ということです。
クラスを使うメリットを言葉で整理する
「データと、そのデータに関する処理をひとまとめにできる」
ここで一度、クラスのメリットを言葉で整理しておきます。
タスクという概念には、
名前
締切
締切までの日数
締切の状態(あと何日か、期限切れか)
といった「データ」と「ロジック」がセットで存在します。
辞書+関数の世界では、
データは辞書
ロジックは外側の関数
としてバラバラに持っていました。
クラスの世界では、
データは self.name, self.deadline
ロジックは remaining_days, status_text
として、ひとつの「Task 型」にまとめられます。
これによって、
タスクに関する処理が散らばらない
コードを読むときに、「タスクって何ができるのか」がクラスを見れば分かる
将来、タスクに新しい機能(例えば「完了フラグ」や「優先度」)を足したくなったときに、Task クラスを中心に変更すればよい
というメリットが生まれます。
11日目で一番大事な感覚
「クラスは“自分で作る新しい型”」
今日あなたに持ってほしい感覚はこれです。
int や str や list や dict は、Pythonが最初から持っている「型」です。
でも、あなたはもう「自分で型を作れる」段階に来ています。
Task
Person
Book
TodoItem
Account
あなたのアプリの中に出てくる「ものたち」を、
クラスとして定義していくことで、
コードは「ただの処理の集まり」から「登場人物のいる物語」に変わっていきます。
クラスは奥が深いですが、
今日やった
class クラス名:__init__ で初期化self.変数 で「そのオブジェクトの状態」を持つdef メソッド(self, ...) で「そのオブジェクト専用の処理」を書く
この4つが押さえられていれば、
もう立派に「クラスを使う人」です。
11日目のまとめ
今日のキーポイントを短く整理すると、こうなります。
クラス(class)は「設計図」、オブジェクト(インスタンス)は「そこから作られた実物」。__init__ は「オブジェクトが作られるときに呼ばれる初期化メソッド」。self は「今扱っているこのオブジェクト自身」を指すキーワード。
Task クラスを作ることで、「タスクのデータ」と「タスクに関する処理」をひとまとめにできる。
辞書のリストは、そのまま「Task オブジェクトのリスト」に置き換えられる。
もし余裕があれば、今日の Task クラスに次のような機能を足してみてください。
タスクに「完了フラグ(done)」を持たせて、mark_done メソッドで完了にするis_overdue メソッドを作って、「期限切れかどうか」を True/False で返すto_line / from_line のようなメソッドを作って、「ファイル用の文字列との変換」をクラス側に持たせる
ここまで来ると、いよいよ「オブジェクト指向プログラミング」の入口に立っています。
残りの日数で、クラスを使ったアプリの形を、もう少しだけ深めていきましょう。
