クラスの基本:オブジェクト指向プログラミング入門#
はじめに#
前回までの記事では、関数について学んできました。関数を使うと、一連の処理をひとまとめにして再利用できるようになります。今回は、プログラミングの重要な概念である「クラス」について学んでいきましょう。
クラスはプログラムを整理するための非常に強力なツールであり、多くのプログラミング言語で採用されている「オブジェクト指向プログラミング」の基本となるものです。実際の現場でのプログラミングでも頻繁に使われる概念ですので、しっかりと理解しておきましょう。
クラスとは?わかりやすく例えてみよう#
クラスとは、データ(属性)と機能(メソッド)をひとまとめにしたものです。でもこれだけでは分かりにくいと思うので、身近な例で考えてみましょう。
設計図と製品の関係#
クラスは「製品の設計図」、オブジェクトは「実際に作られた製品」のようなものです。
- クラス(設計図):どんな特性や機能を持つ製品を作るかを定義するもの
- オブジェクト(製品):その設計図から実際に作られたもの
例えば、スマートフォンの設計図(クラス)が1つあれば、同じ仕様のスマートフォン(オブジェクト)を何台でも製造できます。それぞれのスマートフォンは同じ機能を持ちますが、保存されているデータ(写真や連絡先など)は異なります。それと同じように、クラスから作られる各オブジェクトは、同じ機能を持ちながらも、個別のデータを持つことができます。
シンプルなクラスを作ってみよう#
では実際に、シンプルなクラスを作ってみましょう。例として「商品」を表すクラスを考えます。
# Product(商品)クラスの定義
class Product:
# クラスを初期化するメソッド
def __init__(self, name, price, stock):
self.name = name # 商品名
self.price = price # 価格
self.stock = stock # 在庫数
# 商品情報を表示するメソッド
def display_info(self):
print(f"商品名: {self.name}, 価格: {self.price}円, 在庫: {self.stock}個")
# Productクラスからオブジェクト(インスタンス)を作成
notebook = Product("ノート", 100, 20)
pen = Product("ボールペン", 150, 50)
# オブジェクトのメソッドを呼び出す
notebook.display_info()
pen.display_info()
商品名: ノート, 価格: 100円, 在庫: 20個
商品名: ボールペン, 価格: 150円, 在庫: 50個
このコードでは、Product
というクラスを定義しました。このクラスには、
__init__
メソッド:商品名、価格、在庫数を設定するdisplay_info
メソッド:商品情報を表示する
という2つのメソッドがあります。
Product
クラスからは、notebook
とpen
という2つのオブジェクト(インスタンス)を作成しました。それぞれのオブジェクトは、同じメソッドを持ちながらも、異なる商品名、価格、在庫数を持っています。
クラスの主要な要素を理解しよう#
クラスを理解するためには、次の4つの重要な概念を把握する必要があります。
- クラス:オブジェクトの設計図
- オブジェクト / インスタンス:クラスから作られた実体
- メソッド:クラスに関連付けられた関数
- 属性:オブジェクトが持つデータ(変数)
これらの概念を詳しく見ていきましょう。
クラスとオブジェクト#
クラスは「どのようなデータを持ち、どのような動作をするか」を定義する設計図です。オブジェクト(インスタンスとも呼ばれます)は、そのクラスから作られた実際のモノです。
例えば、Dog
クラスは犬という概念(設計図)を定義し、my_dog
はその設計図から作られた特定の犬(実体)です。
# Dog(犬)クラスの定義
class Dog:
def __init__(self, name, age):
self.name = name # 犬の名前
self.age = age # 犬の年齢
def greet(self):
print(f"わんわん!私は{self.name}です。{self.age}歳です。")
# Dogクラスからmy_dogというオブジェクトを作成
my_dog = Dog("ポチ", 3)
my_dog.greet()
# 別の犬のオブジェクトを作成
another_dog = Dog("シロ", 2)
another_dog.greet()
# どのクラスから作られたか確認
print(f"my_dogの型: {type(my_dog)}")
print(f"another_dogの型: {type(another_dog)}")
わんわん!私はポチです。3歳です。
わんわん!私はシロです。2歳です。
my_dogの型: <class '__main__.Dog'>
another_dogの型: <class '__main__.Dog'>
メソッド#
クラス内で定義された関数を「メソッド」と呼びます。メソッドは、そのクラスのオブジェクトに対して操作を行います。
メソッドを定義するとき、第一引数には常にself
を使います。このself
は、メソッドが呼び出されるオブジェクト自身を指します。メソッドを呼び出すとき、self
には何も渡す必要はありません。Pythonが自動的に呼び出されたオブジェクトをself
に渡してくれます。つまり、my_dog.greet()
を実行すると、greet
メソッド内のself
はmy_dog
を指します。
# メソッドと関数の違いを確認
def normal_function(dog_name, dog_age):
print(f"これは普通の関数です。{dog_name}は{dog_age}歳です。")
# 普通の関数の呼び出し
normal_function("レックス", 4)
# メソッドの呼び出し(selfは自動的に渡される)
my_dog.greet() # このとき、selfにはmy_dogが自動的に渡される
これは普通の関数です。レックスは4歳です。
わんわん!私はポチです。3歳です。
属性#
クラスの属性は、オブジェクトが持つデータを表します。属性は、クラス内ではself
を使ってアクセスします。Dog
クラスで定義したname
やage
は属性です。これらの属性は、オブジェクトごとに異なる値を持つことができます。
クラス外からは、オブジェクト名を指定して属性にアクセスします。
# 属性へのアクセス
print(f"my_dogの名前: {my_dog.name}")
print(f"my_dogの年齢: {my_dog.age}")
# 属性の変更
my_dog.age = 4
print(f"my_dogの新しい年齢: {my_dog.age}")
# 変更後の挨拶
my_dog.greet()
my_dogの名前: ポチ
my_dogの年齢: 3
my_dogの新しい年齢: 4
わんわん!私はポチです。4歳です。
__init__メソッド:オブジェクトの初期化#
__init__
(イニット)メソッドは、クラスのオブジェクトが作成されるときに自動的に呼び出される特別なメソッドです。このメソッドを使って、オブジェクトの初期状態を設定します。
# __init__メソッドについて詳しく見る
class Person:
def __init__(self, name, age):
print(f"新しい人物を作成中: {name}, {age}歳")
self.name = name
self.age = age
def introduce(self):
print(f"こんにちは、私は{self.name}です。{self.age}歳です。")
# Personクラスのオブジェクトを作成
person1 = Person("田中", 28)
person1.introduce()
person2 = Person("佐藤", 35)
person2.introduce()
新しい人物を作成中: 田中, 28歳
こんにちは、私は田中です。28歳です。
新しい人物を作成中: 佐藤, 35歳
こんにちは、私は佐藤です。35歳です。
__init__
メソッドは「コンストラクタ」とも呼ばれ、オブジェクトを「構築」するときに実行されます。この例では、新しいPerson
オブジェクトが作られるたびに、"新しい人物を作成中"というメッセージが表示されています。
より実用的なクラスの例:銀行口座#
もう少し実用的な例として、銀行口座を管理するクラスを作ってみましょう。
class BankAccount:
def __init__(self, account_number, owner_name, balance=0):
self.account_number = account_number
self.owner_name = owner_name
self.balance = balance
def deposit(self, amount):
'''入金する'''
if amount > 0:
self.balance += amount
print(f"{amount}円を入金しました。残高: {self.balance}円")
else:
print("入金額は0より大きい値を指定してください。")
def withdraw(self, amount):
'''引き出す'''
if amount > 0:
if self.balance >= amount:
self.balance -= amount
print(f"{amount}円を引き出しました。残高: {self.balance}円")
else:
print("残高不足です。")
else:
print("引き出し額は0より大きい値を指定してください。")
def get_balance(self):
'''残高を取得する'''
return self.balance
def show_info(self):
'''口座情報を表示する'''
print(f"口座番号: {self.account_number}")
print(f"口座名義: {self.owner_name}")
print(f"残高: {self.balance}円")
# 口座を作る
my_account = BankAccount("1234567", "山田太郎", 10000)
my_account.show_info()
# お金を入金する
my_account.deposit(5000)
# お金を引き出す
my_account.withdraw(2000)
# 残高を確認する
balance = my_account.get_balance()
print(f"現在の残高は{balance}円です。")
# エラーケースの確認
my_account.withdraw(20000) # 残高不足
my_account.deposit(-1000) # 負の入金額
口座番号: 1234567
口座名義: 山田太郎
残高: 10000円
5000円を入金しました。残高: 15000円
2000円を引き出しました。残高: 13000円
現在の残高は13000円です。
残高不足です。
入金額は0より大きい値を指定してください。
このクラスでは、銀行口座の情報(口座番号、名義、残高)を属性として保存し、入金、引き出し、情報表示などの機能をメソッドとして実装しています。
このようにクラスを使うと、関連するデータと操作をひとまとめにして扱うことができます。また、エラーチェック(残高不足、負の入金額など)も一箇所にまとめられるため、コードの管理が容易になります。
クラスを使う利点#
クラスを使うことで、以下のような利点があります。
- コードの整理:関連するデータと機能をひとつの単位にまとめられる
- 再利用性:一度定義したクラスを何度でも使い回せる
- メンテナンス性:機能の追加や変更が容易になる
- データの保護:適切に設計すれば、データの不正な変更を防げる
例えば、上記の銀行口座クラスに新しい機能(利子計算、口座間の送金など)を追加する場合も、既存のコードを変更せずに新しいメソッドを追加するだけでよいです。
まとめ#
この記事では、Pythonにおけるクラスの基本について学びました。
- クラスは、データ(属性)と機能(メソッド)をひとまとめにしたもの
- オブジェクト(インスタンス) は、クラスから作られた実体
- __init__メソッドは、オブジェクトが作成されるときに自動的に呼び出される
- selfは、メソッドが呼び出されるオブジェクト自身を参照する
- クラスを使うと、関連する機能をまとめて管理でき、コードの再利用性が高まる
クラスの概念は最初は少し難しく感じるかもしれませんが、使いこなせるようになると、より整理された、メンテナンスしやすいプログラムが書けるようになります。