Python3でのクラス継承の理解

提供:Dev Guides
移動先:案内検索

序章

オブジェクト指向プログラミングは、再利用可能なコードパターンを作成して、開発プロジェクトの冗長性を削減します。 オブジェクト指向プログラミングがリサイクル可能なコードを実現する1つの方法は、あるサブクラスが別の基本クラスのコードを活用できる場合の継承です。

このチュートリアルでは、親クラスと子クラスの動作、メソッドと属性のオーバーライド方法、super()関数の使用方法、複数の使用方法など、Pythonの継承の主要な側面について説明します。継承。

前提条件

Python 3をインストールし、コンピューターまたはサーバーにプログラミング環境をセットアップする必要があります。 プログラミング環境をセットアップしていない場合は、ローカルプログラミング環境またはサーバー上のプログラミング環境のインストールおよびセットアップガイドを参照して、オペレーティングに適したものにすることができます。システム(Ubuntu、CentOS、Debianなど)

継承とは何ですか?

継承は、クラスが別のクラス内で構築されたコードを使用する場合です。 生物学の観点から遺伝を考えると、子供が親から特定の特性を継承していると考えることができます。 つまり、子供は親の身長または目の色を継承できます。 子供は両親と同じ名前を共有することもできます。

子クラスまたはサブクラスと呼ばれるクラスは、親クラスまたは基本クラスからメソッドと変数を継承します。

last_nameheight、およびeye_colorクラス変数を持つParentという親クラスを子クラスと考えることができます。 ChildParentから継承します。

ChildサブクラスはParent基本クラスを継承しているため、ChildクラスはParentのコードを再利用でき、プログラマーはコードを作成し、冗長性を減らします。

親クラス

親クラスまたは基本クラスは、子またはサブクラスの基になるパターンを作成します。 親クラスを使用すると、毎回同じコードを書き直すことなく、継承を通じて子クラスを作成できます。 どのクラスも親クラスにすることができるので、それらは単なるテンプレートではなく、それ自体で完全に機能するクラスです。

Personal_accountBusiness_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という親クラスがある場合、RhombusParallelogramは、GoldfishFishであるのと同じです。

子クラスの最初の行は、親クラスをパラメーターとして子クラスに渡す必要があるため、非子クラスとは少し異なります。

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オブジェクトcaseyFishメソッド__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_namelast_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_barrierCoralReefオブジェクトとして設定され、両方の親クラスのメソッドを使用できます。 プログラムを実行すると、次の出力が表示されます。

OutputCoral lives in a community.
The anemone is protecting the clownfish.

出力は、両方の親クラスのメソッドが子クラスで効果的に使用されたことを示しています。

多重継承により、子クラスの複数の親クラスからのコードを使用できます。 同じメソッドが複数の親メソッドで定義されている場合、子クラスはタプルリストで宣言された最初の親のメソッドを使用します。

効果的に使用できますが、プログラムが曖昧になったり、他のプログラマーが理解しにくくなったりしないように、多重継承は注意して行う必要があります。

結論

このチュートリアルでは、親クラスと子クラスの構築、子クラス内の親メソッドと属性のオーバーライド、super()関数の使用、および子クラスが複数の親クラスから継承できるようにする方法について説明しました。

オブジェクト指向コーディングの継承により、ソフトウェア開発のDRY(自分自身を繰り返さないでください)の原則を順守できるようになり、少ないコードと繰り返しでより多くのことを実行できるようになります。 また、継承により、プログラマーは、コードが効果的で明確であることを確認するために、作成しているプログラムをどのように設計しているかについて考える必要があります。