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つの引数を受け取り、それぞれをインスタンスの属性として設定しています。
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!
このように、異なるクラスのオブジェクトでも、それぞれが同じメソッド名を持っていれば、そのメソッドを同じように呼び出すことができます。これがポリモーフィズムの一例です。
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入門:学習カリキュラム ←こちらから!