前書き
オブジェクト指向プログラミングは、再利用可能なコードのパターンを作成して、開発プロジェクトの冗長性を削減します。 1つのサブクラスが別の基本クラスのコードを活用できる場合、オブジェクト指向プログラミングがリサイクル可能なコードを実現する1つの方法は継承です。
このチュートリアルでは、親クラスと子クラスの動作、メソッドと属性のオーバーライド方法、super()
関数の使用方法、多重継承の使用方法など、Pythonでの継承の主要な側面について説明します。 。
継承とは
Inheritanceは、クラスが別のクラス内で構築されたコードを使用する場合です。 生物学の観点から継承を考えると、子供が親から特定の特性を継承していると考えることができます。 つまり、子供は親の身長または目の色を継承できます。 また、子供は両親と同じ姓を共有する場合があります。
child classesまたはsubclassesと呼ばれるクラスは、parent classesまたはbase classesからメソッドと変数を継承します。
子クラスChild
が継承するlast_name
、height
、およびeye_color
のclass variablesを持つParent
という親クラスを考えることができます。 Parent
から。
Child
サブクラスはParent
基本クラスから継承しているため、Child
クラスはParent
のコードを再利用でき、プログラマーはより少ないコード行を使用して冗長性を減らすことができます。 。
親クラス
親または基本クラスは、子またはサブクラスのベースとなるパターンを作成します。 親クラスを使用すると、毎回同じコードを書き直すことなく、継承を通じて子クラスを作成できます。 任意のクラスを親クラスにすることができるため、それらはそれぞれ単なるテンプレートではなく、それ自体が完全に機能するクラスです。
Personal_account
とBusiness_account
の子クラスを持つ一般的なBank_account
親クラスがあるとしましょう。 個人口座とビジネス口座の間の方法の多くは、お金を引き出したり預けたりする方法など、類似しているため、それらはBank_account
の親クラスに属することができます。 Business_account
サブクラスには、ビジネスレコードとフォームを収集する方法や、employee_identification_number
変数など、それに固有のメソッドがあります。
同様に、Animal
クラスにはeating()
メソッドとsleeping()
メソッドがあり、Snake
サブクラスには独自のhissing()
メソッドとslithering()
メソッドが含まれている場合があります。
後でサブクラスとして魚のタイプを構築するために使用するFish
親クラスを作成しましょう。 これらの魚にはそれぞれ、特性に加えて名と姓があります。
fish.py
という名前の新しいファイルを作成し、__init__()
constructor methodから始めます。このファイルには、各Fish
オブジェクトのfirst_name
およびlast_name
クラス変数が入力されます。またはサブクラス。
fish.py
class Fish:
def __init__(self, first_name, last_name="Fish"):
self.first_name = first_name
self.last_name = last_name
ほとんどの魚がこれを姓として持つことがわかっているため、last_name
変数を文字列"Fish"
で初期化しました。
他のメソッドも追加しましょう。
fish.py
class Fish:
def __init__(self, first_name, last_name="Fish"):
self.first_name = first_name
self.last_name = last_name
def swim(self):
print("The fish is swimming.")
def swim_backwards(self):
print("The fish can swim backwards.")
メソッドswim()
とswim_backwards()
をFish
クラスに追加したので、すべてのサブクラスもこれらのメソッドを利用できるようになります。
作成する魚のほとんどは、cartilaginous fish(軟骨で作られた骨格を持つ)ではなく、bony fish(骨で作られた骨格を持つ)と見なされるためです。 、__init__()
メソッドにさらにいくつかの属性を追加できます。
fish.py
class Fish:
def __init__(self, first_name, last_name="Fish",
skeleton="bone", eyelids=False):
self.first_name = first_name
self.last_name = last_name
self.skeleton = skeleton
self.eyelids = eyelids
def swim(self):
print("The fish is swimming.")
def swim_backwards(self):
print("The fish can swim backwards.")
親クラスを作成する方法は、他のクラスを作成する方法と同じです。ただし、子クラスで作成したメソッドを子クラスで使用できるようにすることを考えています。
子クラス
子またはサブクラスは、親クラスから継承するクラスです。 これは、各子クラスが親クラスのメソッドと変数を利用できることを意味します。
たとえば、Fish
クラスをサブクラス化するGoldfish
子クラスは、Fish
で宣言されたswim()
メソッドを宣言せずに使用できます。
各子クラスは親クラスのクラスと考えることができます。 つまり、Rhombus
という子クラスとParallelogram
という親クラスがある場合、Rhombus
is aParallelogram
と同じように言うことができます。 Goldfish
is aFish
。
子クラスの最初の行は、親クラスを子クラスにパラメーターとして渡す必要があるため、非子クラスとは少し異なります。
class Trout(Fish):
Trout
クラスは、Fish
クラスの子です。 括弧内にFish
という単語が含まれているため、これがわかります。
子クラスを使用すると、メソッドを追加するか、既存の親メソッドをオーバーライドするか、pass
キーワードを使用してデフォルトの親メソッドを受け入れるかを選択できます。この場合は次のようにします。
fish.py
...
class Trout(Fish):
pass
これで、追加のメソッドを定義することなく、Trout
オブジェクトを作成できます。
fish.py
...
class Trout(Fish):
pass
terry = Trout("Terry")
print(terry.first_name + " " + terry.last_name)
print(terry.skeleton)
print(terry.eyelids)
terry.swim()
terry.swim_backwards()
Trout
子クラスでメソッドを定義していなくても、Fish
クラスの各メソッドを使用するTrout
オブジェクトterry
を作成しました。 他のすべての変数が初期化されたため、"Terry"
の値をfirst_name
変数に渡すだけで済みました。
プログラムを実行すると、次の出力が表示されます。
OutputTerry Fish
bone
False
The fish is swimming.
The fish can swim backwards.
次に、独自のメソッドを含む別の子クラスを作成しましょう。 このクラスをClownfish
と呼びます。その特別なメソッドにより、イソギンチャクと一緒に暮らすことができます。
fish.py
...
class Clownfish(Fish):
def live_with_anemone(self):
print("The clownfish is coexisting with sea anemone.")
次に、Clownfish
オブジェクトを作成して、これがどのように機能するかを確認しましょう。
fish.py
...
casey = Clownfish("Casey")
print(casey.first_name + " " + casey.last_name)
casey.swim()
casey.live_with_anemone()
プログラムを実行すると、次の出力が表示されます。
OutputCasey Fish
The fish is swimming.
The clownfish is coexisting with sea anemone.
出力は、Clownfish
オブジェクトcasey
がFish
メソッド__init__()
とswim()
、およびその子クラスメソッドlive_with_anemone()
を使用できることを示しています。 s。
Trout
オブジェクトでlive_with_anemone()
メソッドを使用しようとすると、エラーが発生します。
Outputterry.live_with_anemone()
AttributeError: 'Trout' object has no attribute 'live_with_anemone'
これは、メソッドlive_with_anemone()
がClownfish
の子クラスにのみ属し、Fish
の親クラスには属していないためです。
子クラスは、それが属する親クラスのメソッドを継承するため、各子クラスはプログラム内でこれらのメソッドを利用できます。
親メソッドのオーバーライド
これまで、pass
キーワードを使用してすべての親クラスFish
の動作を継承する子クラスTrout
と、別の子クラスClownfish
を見てきました。すべての親クラスの動作を継承し、子クラスに固有の独自のメソッドも作成しました。 ただし、場合によっては、すべてではなく親クラスの動作の一部を使用することがあります。 親クラスのメソッドを変更するときは、それらをoverrideします。
親クラスと子クラスを構築するときは、オーバーライドによって不要なコードや冗長なコードが生成されないように、プログラムの設計に留意することが重要です。
Fish
親クラスのShark
子クラスを作成します。 主に硬骨魚を作成するという考えでFish
クラスを作成したため、代わりに軟骨魚であるShark
クラスを調整する必要があります。 プログラム設計に関しては、複数の非骨魚がいる場合、これらの2種類の魚のそれぞれに個別のクラスを作成することをお勧めします。
サメは、骨の多い魚とは異なり、骨ではなく軟骨でできた骨格を持っています。 まぶたもあり、後方に泳ぐことができません。 ただし、サメは沈むことで後方に移動できます。
これに照らして、__init__()
コンストラクターメソッドとswim_backwards()
メソッドをオーバーライドします。 サメは泳ぐことができる魚なので、swim()
メソッドを変更する必要はありません。 この子クラスを見てみましょう。
fish.py
...
class Shark(Fish):
def __init__(self, first_name, last_name="Shark",
skeleton="cartilage", eyelids=True):
self.first_name = first_name
self.last_name = last_name
self.skeleton = skeleton
self.eyelids = eyelids
def swim_backwards(self):
print("The shark cannot swim backwards, but can sink backwards.")
__init__()
メソッドで初期化されたパラメーターをオーバーライドしたため、last_name
変数は文字列"Shark"
と等しく設定され、skeleton
変数は文字列"cartilage"
であり、eyelids
変数がブール値True
に設定されるようになりました。 クラスの各インスタンスは、これらのパラメーターをオーバーライドすることもできます。
swim_backwards()
メソッドは、Fish
の親クラスの文字列とは異なる文字列を出力するようになりました。これは、サメが硬骨魚のように後方に泳ぐことができないためです。
これで、Shark
子クラスのインスタンスを作成できます。これは、Fish
親クラスのswim()
メソッドを引き続き使用します。
fish.py
...
sammy = Shark("Sammy")
print(sammy.first_name + " " + sammy.last_name)
sammy.swim()
sammy.swim_backwards()
print(sammy.eyelids)
print(sammy.skeleton)
このコードを実行すると、次の出力が表示されます。
OutputSammy Shark
The fish is swimming.
The shark cannot swim backwards, but can sink backwards.
True
cartilage
Shark
子クラスは、親クラスのswim()
メソッドを継承しながら、Fish
親クラスの__init__()
およびswim_backwards()
メソッドを正常にオーバーライドしました。
他のクラスよりもユニークな子クラスの数が限られている場合、親クラスのメソッドをオーバーライドすることが有用であることがわかります。
super()
関数
super()
関数を使用すると、クラスオブジェクトで上書きされた継承メソッドにアクセスできます。
super()
関数を使用する場合、親メソッドを子メソッドに呼び出して使用します。 たとえば、親メソッドの特定の機能を特定の機能でオーバーライドした後、元の親メソッドの残りを呼び出してメソッドを終了したい場合があります。
学生を採点するプログラムでは、Grade
の親クラスから継承するWeighted_grade
の子クラスが必要になる場合があります。 子クラスWeighted_grade
では、親クラスのcalculate_grade()
メソッドをオーバーライドして、加重評点を計算する機能を含めながら、元のクラスの残りの機能を保持したい場合があります。 super()
関数を呼び出すことにより、これを実現できます。
super()
関数は、__init__()
メソッド内で最も一般的に使用されます。これは、子クラスに一意性を追加してから、親からの初期化を完了する必要があるためです。
これがどのように機能するかを確認するために、Trout
の子クラスを変更してみましょう。 マスは通常淡水魚なので、water
変数を__init__()
メソッドに追加し、文字列"freshwater"
と同じに設定しますが、残りの親クラスの変数とパラメーターは維持します。
fish.py
...
class Trout(Fish):
def __init__(self, water = "freshwater"):
self.water = water
super().__init__(self)
...
Trout
子クラスの__init__()
メソッドをオーバーライドし、親クラスFish
によって既に定義されている__init__()
の異なる実装を提供します。 Trout
クラスの__init__()
メソッド内で、Fish
クラスの__init__()
メソッドを明示的に呼び出しました。
メソッドをオーバーライドしたため、first_name
をパラメーターとしてTrout
に渡す必要がなくなり、パラメーターを渡した場合は、代わりにfreshwater
をリセットします。 したがって、オブジェクトインスタンスで変数を呼び出すことにより、first_name
を初期化します。
これで、親クラスの初期化された変数を呼び出すことができ、一意の子変数も利用できます。 これをTrout
のインスタンスで使用してみましょう。
fish.py
...
terry = Trout()
# Initialize first name
terry.first_name = "Terry"
# Use parent __init__() through super()
print(terry.first_name + " " + terry.last_name)
print(terry.eyelids)
# Use child __init__() override
print(terry.water)
# Use parent swim() method
terry.swim()
OutputTerry Fish
False
freshwater
The fish is swimming.
出力は、Trout
子クラスのオブジェクトterry
が、子固有の__init__()
変数water
の両方を利用できると同時に、%を呼び出すことができることを示しています。 (t4)sの親__init__()
変数のfirst_name
、last_name
、およびeyelids
。
組み込みのPython関数super()
を使用すると、子クラスのメソッドの特定の側面をオーバーライドする場合でも、親クラスのメソッドを利用できます。
多重継承
Multiple inheritanceは、クラスが複数の親クラスから属性とメソッドを継承できる場合です。 これにより、プログラムは冗長性を減らすことができますが、ある程度の複雑さとあいまいさをもたらす可能性があるため、プログラム全体の設計を考慮して行う必要があります。
多重継承がどのように機能するかを示すために、Coral
クラスとSea_anemone
クラスから継承するよりもCoral_reef
子クラスを作成しましょう。 それぞれにメソッドを作成してから、Coral_reef
子クラスでpass
キーワードを使用できます。
coral_reef.py
class Coral:
def community(self):
print("Coral lives in a community.")
class Anemone:
def protect_clownfish(self):
print("The anemone is protecting the clownfish.")
class CoralReef(Coral, Anemone):
pass
Coral
クラスには1行を出力するcommunity()
というメソッドがあり、Anemone
クラスには別の行を出力するprotect_clownfish()
というメソッドがあります。 次に、両方のクラスを継承tupleに呼び出します。 これは、Coral
が2つの親クラスから継承していることを意味します。
Coral
オブジェクトをインスタンス化してみましょう。
coral_reef.py
...
great_barrier = CoralReef()
great_barrier.community()
great_barrier.protect_clownfish()
オブジェクトgreat_barrier
はCoralReef
オブジェクトとして設定され、両方の親クラスのメソッドを使用できます。 プログラムを実行すると、次の出力が表示されます。
OutputCoral lives in a community.
The anemone is protecting the clownfish.
出力は、両方の親クラスのメソッドが子クラスで効果的に使用されたことを示しています。
多重継承により、子クラスの複数の親クラスのコードを使用できます。 同じメソッドが複数の親メソッドで定義されている場合、子クラスはそのタプルリストで宣言されている最初の親のメソッドを使用します。
多重継承は効果的に使用できますが、他のプログラマーが理解しづらくなり、プログラムがあいまいになったり困難になったりしないように、注意して多重継承を行う必要があります。
結論
このチュートリアルでは、親クラスと子クラスの構築、子クラス内の親メソッドと属性のオーバーライド、super()
関数の使用、および子クラスが複数の親クラスから継承できるようにする方法について説明しました。
オブジェクト指向コーディングの継承により、ソフトウェア開発のDRY(繰り返さないでください)の原則を順守することができ、より少ないコードと繰り返しでより多くのことが可能になります。 継承はまた、コードが効果的で明確であることを保証するために、作成しているプログラムをどのように設計するかをプログラマーに考えるよう促します。