Python3でのクラス継承の理解
序章
オブジェクト指向プログラミングは、再利用可能なコードパターンを作成して、開発プロジェクトの冗長性を削減します。 オブジェクト指向プログラミングがリサイクル可能なコードを実現する1つの方法は、あるサブクラスが別の基本クラスのコードを活用できる場合の継承です。
このチュートリアルでは、親クラスと子クラスの動作、メソッドと属性のオーバーライド方法、super()
関数の使用方法、複数の使用方法など、Pythonの継承の主要な側面について説明します。継承。
前提条件
Python 3をインストールし、コンピューターまたはサーバーにプログラミング環境をセットアップする必要があります。 プログラミング環境をセットアップしていない場合は、ローカルプログラミング環境またはサーバー上のプログラミング環境のインストールおよびセットアップガイドを参照して、オペレーティングに適したものにすることができます。システム(Ubuntu、CentOS、Debianなど)
継承とは何ですか?
継承は、クラスが別のクラス内で構築されたコードを使用する場合です。 生物学の観点から遺伝を考えると、子供が親から特定の特性を継承していると考えることができます。 つまり、子供は親の身長または目の色を継承できます。 子供は両親と同じ名前を共有することもできます。
子クラスまたはサブクラスと呼ばれるクラスは、親クラスまたは基本クラスからメソッドと変数を継承します。
last_name
、height
、およびeye_color
のクラス変数を持つParent
という親クラスを子クラスと考えることができます。 Child
は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
親クラスを作成してみましょう。この親クラスは、後でサブクラスとして魚の種類を作成するために使用します。 これらの魚のそれぞれは、特徴に加えて、名と姓を持ちます。
情報:このチュートリアルのサンプルコードに従うには、python3
コマンドを実行して、ローカルシステムでPythonインタラクティブシェルを開きます。 次に、>>>
プロンプトの後に例を追加して、例をコピー、貼り付け、または編集できます。
fish.py
という名前の新しいファイルを作成し、 __ init __()コンストラクターメソッドから始めます。このメソッドには、first_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
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
クラスに追加しました。これにより、すべてのサブクラスでもこれらのメソッドを使用できるようになります。
作成する魚のほとんどは、軟骨魚ではなく硬骨魚(骨格が骨でできているため)と見なされるためです。軟骨で作られたスケルトン)、__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
はParallelogram
は、Goldfish
がFish
であるのと同じです。
子クラスの最初の行は、親クラスをパラメーターとして子クラスに渡す必要があるため、非子クラスとは少し異なります。
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()
の。
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
は、すべての親クラスの動作を継承し、子クラスに固有の独自のメソッドも作成しました。 ただし、親クラスの動作のすべてではなく、一部を使用したい場合があります。 親クラスのメソッドを変更すると、それらをオーバーライドします。
親クラスと子クラスを作成するときは、オーバーライドによって不要なコードや冗長なコードが生成されないように、プログラムの設計を念頭に置くことが重要です。
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
子クラスは、Fish
親クラスの__init__()
およびswim_backwards()
メソッドを正常にオーバーライドし、同時にswim()
メソッドを継承します。親クラス。
他のクラスよりも一意な子クラスの数が限られている場合は、親クラスのメソッドをオーバーライドすると便利です。
super()
機能
super()
関数を使用すると、クラスオブジェクトで上書きされた継承されたメソッドにアクセスできます。
super()
関数を使用する場合、親メソッドを子メソッドに呼び出して使用します。 たとえば、親メソッドの1つの側面を特定の機能でオーバーライドした後、元の親メソッドの残りの部分を呼び出してメソッドを終了したい場合があります。
生徒を採点するプログラムでは、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
の両方を利用できると同時に、 Fish
の親__init__()
変数をfirst_name
、last_name
、およびeyelids
の呼び出します。
組み込みのPython関数super()
を使用すると、子クラスでこれらのメソッドの特定の側面をオーバーライドする場合でも、親クラスのメソッドを利用できます。
多重継承
多重継承は、クラスが複数の親クラスから属性とメソッドを継承できる場合です。 これにより、プログラムの冗長性を減らすことができますが、ある程度の複雑さとあいまいさをもたらす可能性もあるため、プログラム全体の設計を考慮して行う必要があります。
多重継承がどのように機能するかを示すために、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に呼び出します。 これは、CoralReef
が2つの親クラスから継承していることを意味します。
CoralReef
オブジェクトをインスタンス化してみましょう。
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(自分自身を繰り返さないでください)の原則を順守できるようになり、少ないコードと繰り返しでより多くのことを実行できるようになります。 また、継承により、プログラマーは、コードが効果的で明確であることを確認するために、作成しているプログラムをどのように設計しているかについて考える必要があります。