背景
学生時代に学んでなんとなくは理解していたけど、会社に入って使っていると、ちゃんと説明できなかったり実装できなかったりする技術があることに徐々に気づいていきました。
本記事シリーズでは自分の知識・スキルを定着することと、同じように悩んでいる人の助けになることを目的に記事を書いていきます。
本記事について
- 本記事では、Pythonの「クラス」「継承」「オーバーライド」などの基本概念を整理します。
- クラスに関する基礎概念を整理して、Pythonで簡易な実装ができるようになることが本記事のゴールです。
主要な知識
クラスとインスタンス
- クラスは設計図、インスタンスはその設計図から作られる具体的なオブジェクトです。
- 以後、"中国料理"というクラスを定義しています。中国料理には地域ごとに多種多様な味、作り方、辛さがあり、それらを定義するためのクラスです。
class ChineseDish:
cuisine_type = "中国料理"
def __init__(self, name, region, spicy_level):
self.name = name
self.region = region
self.spicy_level = spicy_level
def describe(self):
print(f"{self.name}は{self.cuisine_type}の代表的な料理です。")
print(f"発祥地: {self.region}")
print(f"辛さレベル: {self.spicy_level}")
コンストラクタ
- Pythonにおいて、コンストラクタとはクラスがインスタンス化されたときに実行される特別なメソッド
__init__
のことを指します。 - 主に初期値の設定に使われます。
- 明示的に親メソッドを呼び出す
super()
によって、super().__init__()
を実行することで、子クラスから親クラスのコンストラクタも呼び出すことができます。
dish = ChineseDish("担々麺","四川","4")
dish.describe()
出力例
担々麺は中国料理の代表的な料理です。
発祥地: 四川
辛さレベル: 4
継承とは
- 親クラスの機能(メソッド)を引き継いで、新たなクラスを定義することです。
- Pythonでは
class 子クラス(親クラス):
という構文で継承を行います。
class SichuanDish(ChineseDish):
def __init__(self,name,region):
super().__init__(name,region,spicy_level=4)
継承を制限する方法
- どのようなクラスでも継承できるわけではなく、意図的に継承を防ぐ設計も可能です。
-
typing.final
や抽象クラスabc
などで、継承・オーバーライドを禁止することができます。
from typing import final
@final
class Base:
pass
# 以下はType Chekerから警告が出る。
# class Derived(Base):
# pass
オーバーライドとは
- オーバーライドとは、親クラスから継承したメソッドを子クラスで同じ名前で再定義して振る舞いを変えることです。
- Pythonでは、子クラスでオーバーライドされたメソッドが優先的に呼ばれます。
class SichuanDish(ChineseDish):
def describe(self):
print(f"{self.name} は四川料理(激辛!)です。")
super().describe()
出力例
担々麺 は四川料理(激辛!)です。
担々麺は中国料理の代表的な料理です。
発祥地: 四川
辛さレベル: 4
カプセル化とは
- カプセル化とは、オブジェクトの内部状態(データ)を外部から直接アクセスできないようにして、メソッドを通じて操作させる設計手法です。(実装TODO)
- Pythonでは、
_変数名
や__変数名
のように名前にアンダースコアをつけて外部からアクセスしにくくします。
print(dish.get_spicy_level())
class ChineseDish:
...
def get_spicy_level(self):
return self._spicy_level
多態性とは
- 多態性(ポリモーフィズム)とは、親クラス型の変数を使ってこクラスのオブジェクトを扱える性質のことです。
- 例えば、
ChineseFood
クラスを継承したSichuanFood
とCantoneseFood
がそれぞれset_spicy_level
メソッドを持っていれば、共通のChineseFood
型としてそれらを扱うことができます。
dishes = [
ChineseDish("饺子", "中国", 1),
SichuanDish("四川麻婆豆腐", "四川")
]
for d in dishes:
d.describe()
super()の使い方
-
super()
は、親クラスのメソッドを呼び出す際に使います。オーバーライドした上で、元の動作を活かしたいときに便利です。
class SpicyDish(ChineseDish):
def __init__(self, name, region):
super().__init__(name, region, spicy_level=5)
print("これは超激辛料理です!")
is-aの関係
- is-a関係とは、クラス設計の原則であり、子クラスが親クラスの一種(a kind of)であることを意味します。
- 例えば、
SichuanFood
はChineseFood
の一種である。→Sichuan food is a Chinese food.
.
その他
アンダースコアの意味は?
-
_name
: 内部利用の慣習。 -
__name
: 名前修飾でサブクラスからの誤使用防止。 -
__init__
; Pythonが自動で呼び出すマジックメソッド -
selfとは?
- インスタンス自身を指すキーワード。インスタンス変数やメソッドにアクセスするために使います。
参考文献
- すっきりわかるJava入門第三部を参考にしつつPython的に解釈しました。