プログラミングを始めると「クラス(class)」という言葉を聞くことが増えてきます。
クラスはある目的を持ったデータと処理をひとまとめに書くことができ、
大きなプログラムを書く上では必須と言えるほど、便利な仕組みです。
今回はそんなクラスの基礎となる用語と使い方について解説します。
初心者の人やもう一度復習したい人は一緒に確認していきましょう!
大きな作品を作りたいなら、ぜひマスターしましょう!
クラスとは?
クラスとは、「ある特定の目的に沿ったデータ」と「そのデータに関する処理」をまとめた設計図です。
一例として、家の情報を管理する目的のクラスをイメージしていきましょう。
皆さんの住んでる家には、住所や築年数などの情報がありますよね。
このように家に関する情報をデータとして、家のクラス内に持つことができます。
次に、築年数から建て替えの時期を知りたい場合を考えてみましょう。
例えば、築年数が50年で建て替えが必要になると判断したいときには、
家のクラス内に持つ築年数のデータと50を比べて判断する処理を用意することになります。
どのようなデータを管理したいかという目的を決め、
目的に沿ったデータと処理をまとめることを意識していきましょう!
# 家クラス.
class House:
def __init__(self, age): # 初期化メソッド.
self.age = age # 家の築年数というデータ.
def is_rebuild_needed(self): # 家の建て替えが必要か判定する処理.
if self.age > 50: # 築50年以上だったら建て替えが必要.
print(f"建て替えよう!")
else:
print(f"まだ必要ないよ!")
クラスの構造と用語の解説
クラスを構成する主な要素は、クラスが管理するデータと処理の2つです。
ですが、クラスをプログラム上で利用する時に多くの用語が登場するので、
よく使用する用語を解説していきます。
- クラス
- オブジェクト
- メンバー変数
- メソッド
class House: # 1. クラス.
rebuild_age_border = 50 # 4.メンバー変数(クラス変数)
# 初期化.
def __init__(self, age): # 2. メソッド(コンストラクタ).
self.age = age # 4.メンバー変数(インスタンス変数).
# 終了処理.
def __del__(self): # 2. メソッド(デストラクタ).
print(f"オブジェクト削除!")
# 家の建て替え判定
def is_rebuild_needed(self): # 2. メソッド.
if self.age > self.rebuild_age_border:
print(f"建て替えよう!")
else:
print(f"まだ必要ないよ!")
# House クラスのインスタンスを作成(コンストラクタが呼び出される).
houseA = House(3) # 3.インスタンス.
houseB = House(5) # 3.インスタンス.
# houseA と houseB は House クラスのインスタンス.
# 同時に、これらはオブジェクトでもある.
# オブジェクト削除(デストラクタが呼び出される).
del houseA
1.クラス
クラスは「ある特定の目的に沿ったデータ」と「そのデータに関する処理」をまとめた設計図です。
後述しますが、データはメンバー変数、処理はメソッドと呼びます。
2.オブジェクト
クラスは設計図であると説明しました。
そのため、使用するときには具体的なデータなどを設定した実体を作る必要があります。
クラスから作成した実体のことを全てオブジェクトと呼びます。
また、特定のクラスから生成されたオブジェクトのことをインスタンスと呼びます。
例えば、家のデータを持つクラスからオブジェクトを作った時に、
“家クラスのインスタンス”という表現をします。
実例の中ではhouseAとhouseBがHouseクラスから生成されたインスタンスであり、
オブジェクトになります。
オブジェクトとインスタンスは、
ほとんど同じ意味なのでどちらを使っても話は通じます
3.メンバー変数
クラス内で定義されるデータのことです。
さらに細かい分類としては、クラス変数とインスタンス変数に分かれています。
クラス変数
同じクラスから生まれたインスタンスで共通して管理する変数です。
プログラムの例では、建て替えを判断する年数であるrebuild_age_borderになります。
使用例ですと、インスタンスが何個生成されたかのカウントや
共通して使う定数の管理などに利用することがあります。
インスタンス間で共通するデータや共有したいデータがあるときに、使いましょう。
インスタンス変数
インスタンスごとに値を変える事ができる変数です。
例では、築年数である”age”が当てはまり、houseAは3、houseBは5を入れています。
インスタンスごとの個性を示すデータを扱う場合に使用しましょう。
インスタンス間で共通する値と個別で持つ値で
定義が変わるということですね
4.メソッド
クラス内で定義される処理のことです。
クラス内に関数定義があるようなイメージです。
例では__init__、__del__、is_rebuild_neededに当てはまります。
__init__と__del__は特殊なメソッドで、それぞれコンストラクタとデストラクタと呼ばれます。
合わせて覚えていきましょう。
コンストラクタ
オブジェクト生成時に呼ばれる特殊なメソッドになります。
コンストラクタに引数を持たせることで、
オブジェクトを作るときにインスタンス変数に値を入れる事も可能です。
デストラクタ
オブジェクト削除時に呼ばれる特殊なメソッドです。
「del (オブジェクト)」での削除やオブジェクトを使用した処理が終了する時に呼ばれます。
クラスは用語が多いので、基本的なものから覚えていきましょう!
クラスの使い方
クラスの基本的な使い方の解説を行っていきます。
さっそく家のクラスを使った実例に沿って確認していきましょう。
# 家クラス.
class House:
rebuild_age_border = 50 # メンバー変数(クラス変数)
def __init__(self, owner, age): # 初期化メソッド.
self.owner = owner # 家の所有者という性質(属性).
self.age = age # 家の築年数という性質(属性).
def is_rebuild_needed(self): # 家の建て替えが必要か判定するメソッド.
if self.age > self.rebuild_age_border: # 築50年以上だったら建て替えが必要.
print(f"建て替えよう!")
else:
print(f"まだ必要ないよ!")
# オブジェクトの作成.
houseA = House('Mike', 20) # houseAという実体を作る.
houseB = House('Jun', 100) # houseBという実体を作る.
# メソッドの使用.
houseA.is_rebuild_needed() # houseAの建て替えの判定 -> "まだ必要ないよ!"
houseB.is_rebuild_needed() # houseBの建て替えの判定 -> "建て替えよう!"
家クラス(House)を作り、そこからhouseAとhouseBのインスタンスを作成しています。
このように1つの設計図(クラス)から複数の実体を作ることもできます。
具体的に説明すると、Mikeが持っている築20年の家をhouseA、
Junが持っている築100年の家をhouseBとしてインスタンスを作成しています。
このように同じ家クラスから作られても異なる情報を持つインスタンスになっています。
そして、インスタンスからメソッドを使って判定することで、
それぞれのインスタンスが持つ個性に応じた結果を得ることができるようになるのです。
例では、is_rebuild_neededで築年数ageというメンバー変数に応じて建て替えの判定を行っています。
クラスという設計図からはインスタンスと呼ばれる実体を作成し、
実体ごとに持つインスタンス変数で個性を出し、メソッドで個性に応じた処理をする流れを覚えていきましょう。
クラスを使うメリット・デメリット
メリット
クラスを使うとプログラムを整理する面で大きな役割を果たします。
ここでは、大きく3点のメリットを解説します
- プログラムの再利用性
- データのカプセル化
- プログラムのメンテナンス性
1. プログラムの再利用性
定義したクラスは、プログラム上のいろいろな場所で使いまわすことができます。
同じプログラムを書くことが減り、プログラムを整理することにもつながります。
# 家クラス.
class House:
def __init__(self, owner, age): # 初期化メソッド.
self.owner = owner # 家の所有者という性質(属性).
self.age = age # 家の築年数という性質(属性).
def is_rebuild_needed(self): # 家の建て替えが必要か判定するメソッド.
if self.age > 50: # 築50年以上だったら建て替えが必要.
print(f"建て替えよう!")
else:
print(f"まだ必要ないよ!")
# オブジェクトの作成.
houseA = House('Mike', 20) # houseAという実体を作る.
houseA.is_rebuild_needed() # houseAの建て替えの判定 -> "まだ必要ないよ!".
# ~~~~~~~~~~~~~~~
# いろんな処理
# ~~~~~~~~~~~~~~~
# すごく離れた場所で, 家のデータ管理が必要になっても OK!.
houseB = House('Jun', 20) # houseBという実体を作る.
houseB.is_rebuild_needed() # houseBの建て替えの判定 -> "建て替えよう!".
2. データのカプセル化
カプセル化は、クラスで管理するデータに外部から直接アクセスできないようにすることです。
これにより、データを意図せずに変更してしまう事態を防ぐことが可能です。
また、直接ではなくメソッドを通じての変更は可能です。
これにより、必ずチェックを入れてから、データを変更するという流れを作ることができます。
例えば、家クラスで築年数の設定にチェックを追加した場合は以下の通りです。
# 家クラス.
class House:
def __init__(self, age): # 初期化メソッド.
self.__age = age # 家の築年数という性質(属性). __をつけることでプライベート属性にする.
@property
def age(self):
return self.__age
# ageに値をセットするときに呼ばれるメソッド.
@age.setter
def age(self, age):
if 0 <= age:
self.__age = age
else:
raise ValueError("値がおかしいよ!")
# オブジェクトの作成.
houseA = House(20) # houseAという実体を作る.
houseA.age = -30 # 値のチェックが入り、"値がおかしいよ!"とエラーが出力.
上記のようにageに”__”をつけることでプライベート属性にし、
外部から直接アクセスできないようにすることが可能です。
また、ageに直接アクセスできないため、ageの値の取得用にゲッター(Getter)と
ageの値の変更用にセッター(Setter)と呼ばれるメソッドを追加しています。
今回はPythonの例なので、プロパティをメソッドにつけています。
ageという名前のメソッドに@propertyをつけてageのゲッター、
@age.setterをつけてageのセッターの定義になります。
例では、セッターの中に設定したい築年数ageが ”0未満か否か” というチェックを入れる事で、
築年数がマイナスになるような不整な値が設定されることを防いでいます。
ageに-30を設定しようとしているため、”値がおかしいよ!”というエラーとなります。
クラス内のデータ管理をより正確に行うためにもカプセル化は利用していきましょう!
3.プログラムのメンテナンス性
クラスは関連するデータと処理をひとまとめにしているため、管理が簡単です。
クラスの機能を拡張したり、動作のテストも専用のメソッドの追加などで気軽に行うことができます。
クラスは再利用・意図しない変更の防止・管理が簡単など、
大きなプログラムを作るのに向いてる機能が多いですね!
デメリット
デメリットとしては2点ほど紹介します。
深刻なものはありませんので、気楽にクラスの習得を進めていきましょう!
- 学習の難易度が高い
- 処理のパフォーマンスの低下
1.学習の難易度が高い
単純に覚えることが多く、使いこなすまで時間がかかることが多いです。
今回は説明から除いていますが、発展として継承・ポリモーフィズム・抽象化などの使い方もあります。
すぐに習得できる人は少ないので気長に進めていきましょう。
2.処理のパフォーマンスの低下
クラスは通常の変数定義や関数呼び出しに比べるとメモリの使用量や計算時間がかかります。
例えば、オブジェクトの生成時には必ずコンストラクタによる処理が呼び出されますし、
メソッドはクラスと結び付けて管理する分のメモリのコストも発生します。
これらはチームで作るような大規模なプログラムを書くことがなければ、問題になることは少ないです。
しかし、重たい処理と改善方法を知ることは、プログラムを続ける上で非常に重要なスキルとなります。
パフォーマンス改善までをこなせる人は少ないので、習得すればレアキャラとして重宝されることでしょう。
メリットの方が大きいので、迷わず習得しましょう!
まとめ
今回はクラスに関する基本となる使い方と用語の解説を行いました。
クラスはデータ管理がしやすく、読みやすいプログラムを書くことに大きな貢献をしてくれます。
読みやすさは自分の書くプログラムをどんどん大きくしていくためには、
必須と言って良いほど追求していくべき最も重要な項目になります。
何年経験しても尽きない話題であり、個人開発だけでなく、チームでの開発、不具合調査、
他の人からのコードレビューなどなど…大いに役に立ちます。
プログラムを読みやすくする術はしっかりと使えるように、成長していきましょう!
読みやすさは正義!読みやすさは正義ですよ!