Pythonのクラスについての理解が浅いため、業務で活用できるよう勉強した。勉強資料としては主にYouTubeと公式ドキュメントを使用した。(参照)
目次
(1)クラスとは
(2)クラスの表現
(3)Constructorの実装
(4)Finalizerの実装
(5)継承
(6)クラスメソッド
(7)スタティックメソッド
1. クラスとは
クラスとは、概念として存在するオブジェクトをインスタンスとして実際に作成するための仕組みである。
クラスの説明をするときは、よく鯛焼き機が例に出される。クラスの概念を鯛焼き機の例に当てはめると以下のようになる。
例 | |
---|---|
オブジェクト | 鯛焼きという概念 |
クラス | 鯛焼き機 |
インスタンス | 鯛焼き |
とにかく、クラスという設計図を作成することで、その設計図のルールに則ったインスタンスという実態を簡単に作成できるようになる。
2. クラスの表現
クラスは「データ」と「処理」によって表現される。
Pythonではこれらのことを特に「クラス変数、インスタンス変数」「メソッド」と呼ぶ。
Pythonでの呼び方 | 説明 | |
---|---|---|
データ | クラス変数 | クラス内で定義された変数 |
データ | インスタンス変数 | インスタンス内で定義された変数 |
処理 | メソッド | クラス内で定義された関数 |
それでは、実際にクラスを定義してみる。
class Taiyaki: #クラスを定義
feature = "oishii!!" #クラス変数を定義
def get_price(self,price,tax): #メソッドを定義
print(price*tax)
t_1 = Taiyaki() #インスタンス化
print(t_1.feature)
# > oishii!!
t_1.store = "shibuya" #アトリビュートを定義
print(t_1.store)
# > shibuya
t_1.get_price(150,1.08) #メソッド実行
# > 162.0
クラスを定義
class Taiyaki: #クラスを定義
class
に続いてクラス名を記述することでクラスTaiyaki
が定義される。
クラス変数を定義
class Taiyaki: #クラスを定義
feature = "oishii!!" #クラス変数を定義
print(t_1.feature)
# > oishii!!
クラス変数は全てのインスタンスで共有される。インスタンスから呼び出す場合、t_1.feature
と()無しで記述すれば良い。
アトリビュートを定義
t_1.store = "shibuya" #アトリビュートを定義
print(t_1.store)
# > shibuya
アトリビュートは各インスタンスに対して定義する。インスタンスt_1
にアトリビュート名store
を繋ぎ、変数を代入する。
このようにインスタンスを作成するたびにアトリビュートを定義するのは、かなり面倒である。
この問題を解消するメソッドとしてConstructorというものがある。Constructorの概要については後述を参照してほしい(3. Constructorの実装)。
クラス変数とインスタンス変数で同じ名前を使用した場合、インスタンス変数が優先される。
メソッドを定義
def get_price(self,price,tax): #メソッドを定義
print(price*tax)
メソッドは、関数と同様にdef
で書き始めて定義する。
ほとんど関数と同様の構造であるが、注意点として、メソッドの引数にはself
を記述しなければならない。self
とはインスタンス自身のことである。つまり、t_1.price()
はt_1.price(t_1)
という実行内容を省略したものになる。私たちは普段意識していないだけで普段からこのようにインスタンスを省略してメソッドを使用している。Pythonの組み込み関数を使用して例を挙げる。
sum([1,2,3])
# > 6
a_list = [1,2,3]
a_list.sum()
# > 6
sum()
は本来、括弧内の第一引数の数値列を合計するものである。しかし、インスタンスを通して呼び出したときは、そのインスタンスを計算対象として扱う(つまりself
を第一引数として扱う)と考えるように実行される。このとき、a_list.sum(a_list)
と書くと見づらいため、引数となるインスタンスは省略して良い、という仕様になっている。
まとめると、Pythonではメソッド内でself
を定義することで引数にオブジェクトを書く手間を省くことができる。
3. Constructorの実装
Constructorとは、メソッドの一種であり、__init__()
というメソッド名で定義する。このメソッドは、インスタンスを作成したときに自動で呼び出されるため、クラスの初期設定に有用である。
先ほど作成したクラスTaiyaki
にConstructorを追加すると下記のようになる。
class Taiyaki: #クラスを定義
def __init__(self,name): #Constructorを定義
self.name = name
def get_price(self,price,tax): #メソッドを定義
print(price*tax)
t_1 = Taiyaki("shibuya") #インスタンス化
print(t_1.name)
# > shibuya
前述の通り、Constructorはインスタンス化と同時に自動で呼び出されるため、コンストラクタ実行に引数が必要な場合はインスタンス自体にその引数を設定する必要がある(Taiyaki("shibuya")
)。
4. Finalizerの実装
Finalizerとは、メソットの一種であり、__del__()
というメソッド名で定義する。このメソッドはインスタンスを削除するためのメソッドである。
class Taiyaki: #クラスを定義
def __init__(self,name): #Constructorを定義
self.name = name
def get_price(self,price,tax): #メソッドを定義
print(price*tax)
def __del__(self): #Finalizerを定義
print("---called del---")
t_1 = Taiyaki("shibuya") #インスタンス化
del t_1 #Finalizer実行
# > ---called del---
5. 継承
継承とは、あるクラスの機能を受け継ぎながら、新しいクラスを定義することである。ここではそれぞれ親クラス、子クラスと呼ぶが、呼び方は色々ある。
呼び方 | |
---|---|
継承元のクラス | 親クラス、基底クラス、スーパークラス |
継承先のクラス | 子クラス、派生クラス、サブクラス |
これによって、既存のクラスと類似しているが僅かに異なる機能を持ったクラスを作成したいときに便利である。
例えば、Taiyaki
クラスを親クラスとして、Ohbanyaki
クラスという子クラスを作成してみよう。
class Taiyaki: #クラスを定義
def __init__(self,name): #Constructorを定義
self.name = name
def get_price(self,price,tax): #メソッドを定義
print(price*tax)
class Ohbanyaki(Taiyaki): #Taiyakiクラスの継承
def get_area(self):
print(3.14*3**2)
t_1 = Taiyaki("shibuya") #インスタンス化
o_1 = Ohbanyaki("shibuya")
print(o_1.get_price(200,1.08)) #親クラスのメソッドを使用
print(o_1.get_area()) #子クラスのメソッドを使用
メソッドのオーバーライド
親クラスのメソッドと同じ名前のメソッドを子クラスで定義した場合、「メソッドのオーバーライドをする」と表現する。
例を示した上で挙動について説明する。
class Taiyaki: #クラスを定義
def __init__(self,name,area): #Constructorを定義
self.name = name
self.area = area
def get_price(self,price,tax): #メソッドを定義
print(price*tax)
class Ohbanyaki(Taiyaki): #Taiyakiクラスの継承
def __init__(self, name, radius) #メソッドのオーバーライド
self.name = name
self.radius = radius
def get_area(self):
print(3.14*self.radius**2)
o_1 = Ohbanyaki("shibuya",3) #インスタンス化
o_1.get_area()
# > 28.26
この場合、子クラスOhbanyaki
のインスタンスを作成したときに、親クラスの__init__()
ではなく、オーバーライドした子クラスの__init__()
が参照される。
注意
オーバーライドされた親クラスのメソッドは、子クラスのインスタンスでは一切使えない。
オーバーライド元のメソッド内容を継承したいときはsuper関数を用いる。
class Taiyaki: #クラスを定義
def __init__(self,name,area): #Constructorを定義
self.name = name
self.area = area
class Ohbanyaki(Taiyaki): #Taiyakiクラスの継承
def __init__(self, name, area) #メソッドのオーバーライド
super().__init__(name,area)
print(self.name)
print(self.area)
6. クラスメソッド
クラスメソッドとは、インスタンスを作成しなくても実行できるクラス内のメソッドのことである。
例を示した上で挙動について説明する。
class Taiyaki: #クラスを定義
feature = "oishii!!"
@classmethod #以下のメソッドをクラスメソッドに変更するデコレータ
def add_feature(cls): #クラスメソッドを定義
cls.feature += "_taiyaki!!"
return cls.feature
print(Taiyaki.add_feature())
# > oishii!!_taiyaki!!
t_1 = Taiyaki()
print(t_1.add_feature()) #インスタンスからクラスメソッドを呼び出すことも可能
# > oishii!!_taiyaki!!
メソッド作成時にインスタンス自身のself
を引数に記述したのと同様に、クラスメソッド作成時にはクラス自身を表すcls
を引数に記述する必要がある。
また、インスタンスからクラスメソッドを呼び出すことも可能である。クラスメソッドはクラスに対する処理であるため、どのようなインスタンスから呼び出しても同じ結果が得られる。
クラスメソッドはデコレータの一種である。
7. スタティックメソッド
スタティックメソッドは、クラスメソッドと同じくインスタンスを作成しなくても実行できるメソッドである。クラスメソッドと異なる点として、クラス自身を表すcls
引数やインスタンス自身を表すself
を引数を受け取らないことである。つまり、実質的な動作内容としては関数と変わらない。
下記に実装例を示す。
class Taiyaki: #クラスを定義
def __init__(self,name,area): #Constructorを定義
self.name = name
self.area = area
@staticmethod #以下のメソッドをスタティックメソッドに変更するデコレータ
def multi(x,y): #スタティックメソッドを定義
return x*y
@staticmethod #以下のメソッドをスタティックメソッドに変更するデコレータ
def call_name(): #スタティックメソッドを定義
print(Taiyaki.name)
print(Taiyaki.multi(3*4))
# > 12
このように、スタティックメソッドの引数にはself
とcls
を入れない。そのため、もしスタティックスタック内でクラス変数を使用したい場合は Taiyaki.name
のようにクラス名から呼び出す必要がある。
スタティックメソッドはデコレータの一種である。
参照
【徹底解説】Pythonのクラスの基本からクラス継承やクラス変数などまでわかりやすく|クラスの使い方も解説【Python入門・応用21】