クラスとオブジェクト
ここまでのいくつかのレッスンでは、関数を使ってコードを整理する——「何をするか」に焦点を当てた「手続き型」アプローチをとってきました。オブジェクト指向プログラミング(OOP)は「誰がするか」に焦点を当て、データとそのデータを操作するメソッドをオブジェクトにパッケージ化します。Python のすべてはオブジェクトです。OOP を理解することは重要な前進です。
1. クラスとオブジェクトとは
クラスは設計図であり、オブジェクトはその設計図から作成された具体的なインスタンスです。
# 「Dog」クラスを定義 — 設計図
class Dog:
pass
# 設計図から具体的な「Dog」オブジェクトを作成
my_dog = Dog()
print(type(my_dog)) # <class '__main__.Dog'>
print(my_dog) # <__main__.Dog object at 0x...>
「犬」という品種が概念(クラス)であるのと同様に、あなたが飼っている特定の犬のワンちゃんはインスタンス(オブジェクト)です。1 つのクラスから無数のオブジェクトを作成できます。
2. __init__:コンストラクタメソッド
オブジェクトを作成するとき、__init__ メソッドが自動的に呼び出され、オブジェクトの属性を初期化します:
class Dog:
"""Dog class"""
def __init__(self, name, age):
self.name = name # インスタンス属性
self.age = age
# オブジェクト作成時にパラメータを渡す
dog1 = Dog("Wangcai", 3)
dog2 = Dog("Xiaobai", 1)
print(dog1.name) # Wangcai
print(dog2.name) # Xiaobai
print(dog1.age) # 3
__init__ はコンストラクタではありません——オブジェクトはそれが呼び出される前に作成されます。実際のコンストラクタは __new__ ですが、それに触れる必要はほとんどありません。__init__ の最初のパラメータは常に self で、現在のオブジェクトインスタンスを表します。
例:Student クラスの定義(難易度 ⭐)
class Student:
"""Student class"""
def __init__(self, name, student_id, score):
self.name = name
self.student_id = student_id
self.score = score
def introduce(self):
"""自己紹介"""
return f"My name is {self.name}, ID: {self.student_id}, score: {self.score}."
def is_pass(self):
"""合格かどうかを確認"""
return self.score >= 60
# 学生オブジェクトを作成
s1 = Student("Zhang San", "2024001", 85)
s2 = Student("Li Si", "2024002", 45)
print(s1.introduce()) # My name is Zhang San, ID: 2024001, score: 85.
print(s2.introduce()) # My name is Li Si, ID: 2024002, score: 45.
print(f"Is Zhang San passing? {s1.is_pass()}") # True
print(f"Is Li Si passing? {s2.is_pass()}") # False
3. メソッド:オブジェクトの振る舞い
クラス内で定義された関数をメソッドと呼びます。最初のパラメータは常に self で、メソッドを呼び出すオブジェクト自体を表します。
class Calculator:
"""簡易電卓"""
def __init__(self):
self.result = 0
def add(self, value):
self.result += value
return self
def subtract(self, value):
self.result -= value
return self
def show(self):
return self.result
calc = Calculator()
calc.add(10)
calc.subtract(3)
print(calc.show()) # 7
# メソッドチェーン — 各メソッドが self を返す
result = Calculator().add(10).subtract(3).add(5).show()
print(result) # 12
self を返すメソッドはチェーンできます。多くの Python ライブラリ(pandas など)がこのパターンを広く使用しています。
4. インスタンス属性 vs クラス属性
属性はインスタンス(各オブジェクトに固有)またはクラス(すべてのオブジェクトで共有)に定義できます:
class Student:
# クラス属性 — すべての学生で共有
school = "First High School"
total_count = 0
def __init__(self, name):
# インスタンス属性 — 各学生に固有
self.name = name
Student.total_count += 1
s1 = Student("Zhang San")
s2 = Student("Li Si")
# クラス属性はクラス名でアクセス
print(Student.school) # First High School
print(Student.total_count) # 2
# インスタンスからもアクセス可能(同名のインスタンス属性がない場合)
print(s1.school) # First High School
print(s2.school) # First High School
# クラス属性の変更はすべてのインスタンスに影響
Student.school = "Second High School"
print(s1.school) # Second High School
例:銀行口座(難易度 ⭐⭐)
class BankAccount:
"""銀行口座"""
bank_name = "Python Bank" # クラス属性
interest_rate = 0.003 # 年利 0.3%
def __init__(self, owner, balance=0):
self.owner = owner # インスタンス属性
self.balance = balance # インスタンス属性
def deposit(self, amount):
self.balance += amount
return f"Deposited {amount}, balance: {self.balance}"
def withdraw(self, amount):
if amount > self.balance:
return "Insufficient balance!"
self.balance -= amount
return f"Withdrew {amount}, balance: {self.balance}"
def yearly_interest(self):
"""年間利息を計算"""
interest = self.balance * BankAccount.interest_rate
return f"Yearly interest: {interest:.2f}"
acc1 = BankAccount("Zhang San", 10000)
acc2 = BankAccount("Li Si", 5000)
print(acc1.deposit(5000)) # Deposited 5000, balance: 15000
print(acc2.withdraw(2000)) # Withdrew 2000, balance: 3000
print(acc1.yearly_interest()) # Yearly interest: 4.50
# すべての口座が同じ金利を共有
print(acc1.interest_rate) # 0.003
print(acc2.interest_rate) # 0.003
よくあるユースケース
- データモデリング:現実世界のエンティティをコードにマッピング——ユーザー、注文、製品はすべてクラスで表現
- 状態管理:オブジェクトが状態(属性)を保持し、メソッドがその状態を操作——例:ゲームキャラクター、ショッピングカート
- コード整理:関連するデータと関数を一緒にパッケージ化。分散した関数よりもクリーン
- フレームワーク拡張:Django のモデル、Flask のアプリケーション、GUI コンポーネントはすべてクラスで実装
❓ よくある質問
self を最初のパラメータとして持ちます。関数は独立して存在できます。メソッドはオブジェクトまたはクラスを介して呼び出す必要があります。本質的に、メソッドは Python が呼び出し元を最初の引数として自動的に渡す関数です。self を他の名前に変更できますか?self は Python コミュニティの固いルールです。名前を変更しても機能はしますが、コードを読む人(将来の自分を含む)が違和感を持ちます。常に self を使用してください。📖 まとめ
- クラスは設計図。オブジェクトはそれから作成された具体的なインスタンス
__init__は初期化メソッド。オブジェクト作成時に自動呼び出し- メソッドの最初のパラメータは
selfで、現在のオブジェクトを表す - インスタンス属性は各オブジェクトに固有。クラス属性はすべてのオブジェクトで共有
- クラスはデータとそれを操作するメソッドを一緒にパッケージ化
📝 練習問題
-
初級(難易度 ⭐):
Carクラスを定義し、brand、color、speed属性を持たせます。速度を上げるaccelerate(value)メソッドと現在の速度を表示するshow_speed()メソッドを含めてください。 -
中級(難易度 ⭐⭐):
Studentクラスを定義します。クラス属性で学生の総数を追跡し、インスタンス属性で各学生の名前とスコアを記録します。英字グレード(A、B、C、D)を返すget_grade()メソッドを実装してください。 -
上級(難易度 ⭐⭐⭐):
LibraryクラスとBookクラスを定義します。Bookはタイトル、著者、貸出状態を持ちます。Libraryは 4 つのメソッドadd_book(book)、borrow(title)、return_book(title)、show_books()を持ちます。



