Pythonのクラスとは、関連する変数とメソッドをまとめた設計図のようなもので、これにより新しいオブジェクト(インスタンス)を生成することができます。
参考 Pythonの特徴

Pythonのクラスはプログラミング初心者にとっては難しく感じるかもしれません。
クラスはPythonプログラミングの基本概念であり、Pythonを使ってソフトウェアを開発するためには、クラスを理解して活用することが重要です。このページでは、Python初心者がクラスの概念を理解し、自分自身でクラスを作成できるようになるための基本的なガイドを提供します。

クラスの基本概念から実際のサンプルコードまで1から丁寧に解説します。
Pythonエンジニアを目指す方であれば知らないと恥ずかしい超・基本知識の1つです。是非最後までご覧ください。
Python:クラスとは
クラスは、オブジェクト指向プログラミング言語における非常に重要な概念です。しかし、この「クラス」という単語が何を意味するのかを理解するのは、プログラミング初心者にとって少し難しいかもしれません。
参考 プログラミングとは?

まずはこのページの前提知識―。「クラスとは何か」を詳しく見ていきましょう。
簡単な日常生活の例を使ってご説明します。まず、クラスとは何かを理解するために、車を作る工程を思い浮かべてみてください。あなたは自動車メーカーに勤めていて、新型の車を作りたいと思ったとしましょう。
その際、最初に行う工程が「設計図を作成すること」になるはずです。いきなり車の部品を作り始めるのではなく、車の「形」や「サイズ」「色」や「部品の構成」に加えて、アクセルやブレーキなど、どのような機能を持つべきかを定義する必要があるでしょう。
自動車メーカーは車を1台だけ作ればよいわけではなく、100台~10000台と製造する必要があるので、設計図を作成することは重要な作業になります。

結論を言うと「クラスとは、この設計図のようなもの」です。
どのようなデータ(属性)を持ち、どのような動作(メソッド)をするべきかを定義するのが、クラスを定義するということになります。
車の設計図の例で言えば、データ(属性)とは「車の色」「車種」「製造年」などがそれに該当します。
動作(メソッド)とは「アクセルを踏む」、「ブレーキを踏む」、「ハンドルを切る」などを指します。

設計図があれば、その設計図に従って具体的な車を製造することができます。これがプログラミングにおける「インスタンス化」に相当します。設計図(クラス)をもとに具体的な車(インスタンス)を作るのです。


クラスを説明するための例は無数にあります。このページでは「車」を例に説明しましたが、他にもいろいろな説明が可能。
「車」ではちょっとわかりづらかった・・・という方に何個か例を挙げて補足します。
これらの例から分かるように、クラスはそのオブジェクトが持つべき基本的な属性とメソッドを定義するための「設計図」のようなものだと理解しておきましょう!

以下にPythonにおけるクラス定義のサンプルコードを記載します。文法の詳細についてはページ後半で詳しく解説しているので、ここでは何となくPythonにおけるクラスのイメージを理解することができればOK。気軽に眺めてみてください。
# クラスの定義(車の設計図)
class Car:
def __init__(self, color, model, year):
self.color = color
self.model = model
self.year = year
def accelerate(self):
print("アクセルを踏む")
def brake(self):
print("ブレーキを踏む")
# インスタンス化(自動車を製造する)
my_ferrari = Car('赤', 'フェラーリ', 2023)
参考 def文
Carはクラス名(設計図の名前)を、color、model、yearは属性(車の特性)。accelerate、brakeはメソッド(車ができる動作)を表しています。このクラスを用いて、「赤色のフェラーリ、製造年は2023年」のような具体的な車を作ることができます。
このように、クラスとは一種の設計図であり、その設計図に基づいて同じ特性を持つオブジェクト(=新型の車)を繰り返し作成することができます。これにより、コードの再利用性の向上させたり、プログラム全体の構造化を行ったりすることが可能になります。

クラスとは何か?が何となくイメージできたところで、ここからは実際のクラスの定義方法を詳しく解説していきます。
サンプルコード付きで1つ1つ丁寧に説明しますので、焦らずゆっくり学習していきましょう。
Python:クラスの定義方法
Pythonにおけるクラスの定義は以下の形式を基本とします。
class ClassName:
def __init__(self, 属性1, 属性2, ...):
self.属性1 = 属性1
self.属性1 = 属性1
...
def メソッド1(self, ...):
# メソッド1の処理内容
def メソッド2(self, ...):
# メソッド2の処理内容

以下に具体的な例を示します。
class Dog:
def __init__(self, name, age):
self.name = name
self.age = age
def bark(self):
print(f"{self.name}は吠えます。ワンワン!")
def get_age(self):
return self.age
この例では、Dogというクラスを定義しています。このクラスにはnameとageという2つの属性と、barkとget_ageという2つのメソッドが存在します。

これでクラスの定義は終了。ここからインスタンス化やメソッドの呼び出しといった具体的な処理を行っていくことになります。
Python:インスタンスの生成(インスタンス化)
インスタンスの生成(インスタンス化)とは、クラスからオブジェクトを生成することです。

つまり、先ほど定義したクラス(設計図)から具体的なオブジェクト(製品)を作成するプロセスがインスタンス化です。具体的なオブジェクトを作成することで、クラスに定義された属性とメソッドを利用することができるようになります。
つまり、クラスを定義しただけではまだ実際に「もの」は作られていないということ。インスタンス化をすることによって、はじめて「もの」がこの世に誕生するイメージです。
Pythonでクラスのインスタンス化を行うには、クラス名を関数のように呼び出します。この際、必要に応じて引数を渡すことができます。これらの引数は、クラスの__init__メソッドに渡され、インスタンスの初期化に使用されます。
class Dog:
def __init__(self, name, age):
self.name = name
self.age = age
def bark(self):
print(f"{self.name}は吠えます。ワンワン!")
def get_age(self):
return self.age
# クラスのインスタンス化
my_dog = Dog("ポチ", 5)
この例では、まずDogクラスを定義しています。次に、my_dog = Dog("ポチ", 5)の行でDogクラスの新しいインスタンスを作成(インスタンス化)しています。
これで my_dog という「犬」が実際に誕生したことになります。

この際、"ポチ"と5という2つの引数を渡しています。これらの引数はDogクラスの__init__メソッドにmy_dogインスタンスのnameとageに引き渡されます(=つまり、名前は「ポチ」で年齢は「5歳」という犬を誕生させていることになります。)
クラス:属性の参照
続いてこのインスタンスの属性を参照してみましょう。
インスタンスの属性にアクセスするためには、.(ドット)を使い、インスタンス名の後に属性名を書きます。
class Dog:
def __init__(self, name, age):
self.name = name
self.age = age
def bark(self):
print(f"{self.name}は吠えます。ワンワン!")
def get_age(self):
return self.age
# クラスのインスタンス化
my_dog = Dog("ポチ", 5)
# インスタンスの属性にアクセスする
print(my_dog.name) # my_dogインスタンスのname属性にアクセスします。出力:ポチ

my_dog の name属性は「ポチ」でインスタンス化されているため、それを出力した結果は勿論「ポチ」となります。
クラス:メソッドの呼び出し
最後にインスタンスのメソッドを呼び出す方法です。メソッドを呼び出すためには、インスタンス名の後に.(ドット)とメソッド名を書きます。
class Dog:
def __init__(self, name, age):
self.name = name
self.age = age
def bark(self):
print(f"{self.name}は吠えます。ワンワン!")
def get_age(self):
return self.age
# クラスのインスタンス化
my_dog = Dog("ポチ", 5)
# インスタンスの属性にアクセスする
print(my_dog.name) # my_dogインスタンスのname属性にアクセスします。出力:ポチ
# インスタンスのメソッドを呼び出す
print(my_dog.bark()) # my_dogインスタンスのbarkメソッドを呼び出します。出力:ポチ says woof!

メソッド名の後には()(括弧)が必要で、これがないとメソッドは呼び出されない点に注意しましょう!
Python:__init__(コンストラクタ / 初期化メソッド)
初期化メソッドとは、クラスから新しいインスタンスが生成されるときに自動的に呼び出される特別なメソッドのことを指します。Pythonでは、このメソッドは__init__という名前で定義されます。

言い換えると、インスタンスが作られる場合に、一番最初に一度だけ必ず呼び出されるメソッドが「初期化メソッド」ということになります。
初期化メソッドは主に、インスタンスが持つ属性を初期化するために使用されます。以下に具体的な例を示します。
class Dog:
def __init__(self, name, age):
self.name = name
self.age = age
この例では、Dogクラスの初期化メソッドがnameとageという2つの引数を受け取り、それぞれをインスタンスの属性として設定しています。
selfは特別な引数で、Pythonが自動的にその値を提供します。具体的には、selfはメソッドを呼び出したオブジェクト(インスタンス)自身を指します。

たとえば、以下のようなDogクラスを定義し、新しいインスタンスを作成したとしましょう。
class Dog:
def __init__(self, name, age):
self.name = name
self.age = age
my_dog = Dog("ポチ", 5)
この場合、Dog("ポチ", 5)というコードを実行するとき、Pythonはまず新しいDogインスタンスを作成し(これがselfになります)、次にその新しいインスタンスと一緒に"ポチ"と5を__init__メソッドに渡します。
したがって、クラスを利用する人から見ると、Dogクラスの初期化メソッドは2つの引数("ポチ"と5)を取りますが、クラスの定義者(クラスを書く人)から見ると、__init__メソッドは3つの引数(self、name、age)を取るということになります。

このself引数の存在はPythonのクラス定義の特徴的な部分であり、メソッド内でそのインスタンス自身にアクセスするための手段を提供するために必須となります。
Python:__del__(デストラクタ)
デストラクタとは、クラスのインスタンスが不要になり、メモリから消去されるときに自動的に呼び出される特別なメソッドのことを指します。Pythonでは、このメソッドは__del__という名前で定義されます。
class Dog:
def __init__(self, name, age):
self.name = name
self.age = age
print(f"{self.name}が生まれました。")
def __del__(self):
print(f"{self.name}はこの世を去りました。")
この例では、Dogクラスのデストラクタが__del__メソッドとして定義されています。
このメソッドは、Dogインスタンスが消去されるときに自動的に呼び出されます。ただし、この例はあくまでもサンプルであり、実際のプログラムではデストラクタの使用は通常推奨されないという点に注意。

Pythonの場合、ガベージコレクション(不要なオブジェクトの自動消去)のメカニズムにより、デストラクタが正確なタイミングで呼び出されることは保証されません。そのため、デストラクタを使用するよりも、リソースの解放などを行うための明示的なメソッドを提供する方が一般的に推奨されます。
Python:クラス変数とインスタンス変数
Pythonのクラスには、クラス変数とインスタンス変数という2種類の変数があります。これらはそのスコープと生存期間、そして使い方により異なります。

Pythonのクラスをマスターするために重要なポイントとなるので、以下にそれぞれの変数の意味・役割・概念を詳しく解説します。
参考 Python 変数の基本
Python:クラス変数
クラス変数は、クラス定義の中で直接定義されます。つまり、メソッドの外側で、そしてクラスブロック内で定義されます。
class Dog:
species = "Canis familiaris" # クラス変数
def __init__(self, name, age):
self.name = name # インスタンス変数
self.age = age # インスタンス変数
クラス変数は、そのクラスから生成されたすべてのインスタンス間で共有されます。つまり、ひとつのインスタンスで行われた変更は他のすべてのインスタンスに影響を及ぼす可能性があります。
これはすべてのインスタンスが同一のクラス変数を参照しているためです。したがって、クラス変数は一般的にすべてのインスタンスに共通する値を保持するのに使用されます。

この例では、speciesはクラス変数です。したがって、すべてのDogインスタンスは同じspeciesを共有します。
Python:インスタンス変数
インスタンス変数は特定のクラスのインスタンスに属する変数で、そのスコープはそのインスタンスに限定されます。つまり、インスタンス変数はそのインスタンスによってのみアクセス可能であり、そのインスタンスで行われた変更はそのインスタンスにのみ影響します。

これは、インスタンス変数が各インスタンスに属しているためで、そのため、各インスタンスは独自の値を保持できます。インスタンス変数は通常、__init__メソッド内で、selfを用いて初期化されます。このselfは現在のインスタンスを参照します。
以下のDogクラスの例で言えば、nameとageはインスタンス変数です。したがって、Dogクラスの各インスタンスはそれぞれ独自のnameとageを持ちます。
class Dog:
species = "Canis familiaris" # クラス変数
def __init__(self, name, age):
self.name = name # インスタンス変数
self.age = age # インスタンス変数
これらの変数の使い方を理解することは、Pythonでのオブジェクト指向プログラミングを理解する上で非常に重要です。クラス変数は、すべてのインスタンスが共有するデータを表現するのに適しています。一方、インスタンス変数はインスタンスごとに固有の情報を表現するのに最適です。
サンプル クラス変数とインスタンス変数
class Dog:
# クラス変数
species = "Canis familiaris"
def __init__(self, name, age):
# インスタンス変数
self.name = name
self.age = age
# インスタンスの作成
dog1 = Dog("ポチ", 3)
dog2 = Dog("シロ", 4)
print("----- クラス変数 -----")
print(dog1.species) # Canis familiaris
print(dog2.species) # Canis familiaris
print("----- インスタンス変数 -----")
print(dog1.name) # ポチ
print(dog2.name) # シロ
print("----- クラス変数を変更 -----")
Dog.species = "Canis lupus"
print(dog1.species) # Canis lupus
print(dog2.species) # Canis lupus
print("----- インスタンス変数を変更 -----")
dog1.name = "タロウ"
print(dog1.name) # タロウ
print(dog2.name) # シロ(変更なし)
この例では、speciesはクラス変数として定義されています。したがって、この変数の値はすべてのDogインスタンスで共有されます。Dog.speciesを変更すると、全てのDogインスタンスのspeciesが変わります。
一方、nameとageは__init__メソッド内で定義されたインスタンス変数です。したがって、これらの変数の値はそれぞれのDogインスタンスに固有であり、一つのインスタンスでこれらの変数の値を変更しても、他のインスタンスには影響を及ぼしません。

クラスの定義やメソッドの呼び出し、変数のスコープなどについて学習してきました。
覚える内容がたくさんあったと思うので、ひとまずここでクラス定義の基本を復習しておきましょう!
Python:継承
クラスの基本を学習したところで、さらに実践的なコーディングが行えるようにより専門的な内容である「継承」という概念について解説します。
継承とは、あるクラスの特性を別のクラスが受け継ぐという概念で、これによりすでに定義されたクラスのコードを再利用し、必要に応じてそのクラスを拡張またはカスタマイズすることが可能になります。

クラスからさらに別のクラスを作る、というイメージ。
継承するクラス(新しいクラス)を派生クラスまたは子クラス、継承されるクラス(既存のクラス)を基底クラスまたは親クラスと呼びます。
Pythonでは、継承を行うためには以下の構文を使用します。
class DerivedClassName(BaseClassName):
<statement-1>
.
.
.
<statement-N>

ここでBaseClassNameは既存のクラス(親クラス)の名前で、DerivedClassNameは新しく作成するクラス(子クラス)の名前です。この構文により、子クラスは親クラスの属性やメソッドを引き継ぎます。
例として、先ほど定義したDogクラスを親クラスとして、新しいBulldogクラスを作成してみます。
# 親クラスの定義
class Dog:
species = "Canis familiaris"
def __init__(self, name, age):
self.name = name
self.age = age
# 子クラスの定義
class Bulldog(Dog):
pass
# インスタンスの作成
my_dog = Bulldog("Max", 5)
print(my_dog.name) # Max
print(my_dog.age) # 5
print(my_dog.species) # Canis familiaris
ここで、Bulldogクラスは親クラスであるDogクラスからspecies属性と__init__メソッドを継承しています。したがって、Bulldogのインスタンスを作成したときにnameとageを渡すことができ、またspecies属性にアクセスすることができます。
なお、継承したクラスでは新たにメソッドを追加したり、親クラスのメソッドを上書き(オーバーライド)することも可能です。これにより、既存のクラスを基にして新しい振る舞いを持つクラスを効率的に作成することができます。
サンプル 継承(新たなメソッドを追加)
class Dog:
species = "Canis familiaris"
def __init__(self, name, age):
self.name = name
self.age = age
def description(self):
return f"{self.name} is {self.age} years old"
class Bulldog(Dog):
def run(self, speed):
return f"{self.name} runs at {speed}km/h"
# Bulldogクラスのインスタンスを作成
jim = Bulldog("Jim", 5)
print(jim.description()) # Jim is 5 years old
print(jim.run(10)) # Jim runs at 10km/h
この例では、Bulldogクラスは親クラスDogからdescriptionメソッドを継承しています。さらに、新たにrunメソッドを追加しています。
サンプル 継承(親クラスのメソッドを上書き(オーバーライド))
class Dog:
species = "Canis familiaris"
def __init__(self, name, age):
self.name = name
self.age = age
def description(self):
return f"{self.name} is {self.age} years old"
class Bulldog(Dog):
def description(self):
return f"{self.name} is a cool dog!"
# Bulldogクラスのインスタンスを作成
jim = Bulldog("Jim", 5)
print(jim.description()) # Jim is a cool dog!
この例では、Bulldogクラスは親クラスDogからdescriptionメソッドを継承していますが、同じ名前のメソッドを新たに定義することでオーバーライドしています。したがって、Bulldogクラスのインスタンスでdescriptionメソッドを呼び出すと、新しく定義したメソッドが使われます。
Python:ポリモーフィズム(Polymorphism)

続いてクラスを理解するために重要な「ポリモーフィズム」という概念について解説します。
ポリモーフィズムとは、「多態性」を意味する言葉で、同一のインターフェースで異なる動作をする能力を指します。Pythonでは、異なるクラスのオブジェクトでも、それぞれが同じ名前のメソッドを持っていれば、そのメソッドを共通のインターフェースとして扱うことができます。これにより、クラスの実装に依存せずにオブジェクトを一貫した方法で扱うことが可能になります。

例えば、以下のような異なるクラスがあるとします。
class Dog:
def make_sound(self):
return "Woof!"
class Cat:
def make_sound(self):
return "Meow!"
ここでは、DogクラスとCatクラスの両方がmake_soundメソッドを持っています。これらのクラスのインスタンスを作成し、それぞれに対してmake_soundメソッドを呼び出すことができます。
dog = Dog() print(dog.make_sound()) # Woof! cat = Cat() print(cat.make_sound()) # Meow!
このように、異なるクラスのオブジェクトでも、それぞれが同じメソッド名を持っていれば、そのメソッドを同じように呼び出すことができます。これがポリモーフィズムの一例です。

上記の説明だけでは、結局何がうれしいの・・・?と思った方へより詳しくポリモーフィズムについて説明しておきます。
ポリモーフィズムを持つということは、一度定義した関数やメソッドを、異なるクラスのオブジェクトに対して共通に適用することができる!ということを意味します。
以下に具体的なサンプルコードを示します。まず、異なる2つのクラス、DogとCatを作成しましょう。これらのクラスは、それぞれvoiceというメソッドを持つこととします。
class Dog:
def voice(self):
return "Woof!"
class Cat:
def voice(self):
return "Meow!"
次に、これらのクラスを使用するmake_voiceという関数を定義します。
def make_voice(animal):
return animal.voice()
参考 関数(def文)

この関数は、引数としてDogまたはCatクラスのオブジェクト(インスタンス)を受け取り、そのvoiceメソッドを呼び出します。以下に使用例を示します。
dog = Dog() cat = Cat() print(make_voice(dog)) # "Woof!" print(make_voice(cat)) # "Meow!"
この例では、DogクラスとCatクラスは異なりますが、どちらもvoiceというメソッドを持っています。そのため、make_voice関数はどちらのクラスのオブジェクトに対しても呼び出すことができます。
これがポリモーフィズムの基本的な考え方であり、その有用性を示す一例です。これにより、異なるクラスのオブジェクトを同一の方法で扱うことができ、コードの再利用性と柔軟性が大いに向上します。
Python:カプセル化(Encapsulation)

最後にカプセル化という概念について。
カプセル化とは、オブジェクトの状態(データ)と振る舞い(メソッド)を一つにまとめ、データを外部から直接操作することを制限するプログラミングの手法を指します。これにより、クラスの内部構造や処理手順を外部から隠蔽することが可能になります。

Pythonでは、クラスのメソッドや変数の名前の前にアンダースコア(_)を1つまたは2つ付けることで、それらを外部から隠蔽することが一般的に行われます。アンダースコアを2つ付けた場合は、クラスの外部から直接アクセスすることができなくなります。
class BankAccount:
def __init__(self, name, balance):
self.__name = name
self.__balance = balance
def deposit(self, amount):
self.__balance += amount
def withdraw(self, amount):
if self.__balance >= amount:
self.__balance -= amount
else:
print("Insufficient balance")
def get_balance(self):
return self.__balance
この例では、BankAccountクラスの__nameと__balance変数は、クラスの外部から直接アクセスすることができません。また、depositメソッドとwithdrawメソッドを通じて、その変数の値を適切な方法で操作することができます。これがカプセル化の一例です。

しかし、注意点として、カプセル化を行うと、一部の機能がクラスの外部から利用できなくなる可能性があります。そのため、どの属性やメソッドを公開するか、どの程度までアクセスを制限するかは慎重に決定する必要があります。また、カプセル化を行いすぎると、クラスの柔軟性が損なわれる場合もあります。
Python:クラスのまとめ

始めてPythonを勉強するのは結構難しいですよね。
でもその悩みを抱えているのは一人じゃありません。全てのPython使いが同じ道を進んできました。
Pythonをはじめとするプログラミングスキルを武器に、時間と場所に捉われない自由な生き方を目指してみませんか?今すぐ行動したい方は以下の記事をチェック!
読者料典 Python入門:学習カリキュラム ←こちらから!
