Python : オブジェクト指向と継承

Python
スポンサーリンク

今回は、オブジェクト指向と継承についてお話していきます。

 

1.オブジェクト指向とは

まずオブジェクト指向とは何かを理解しましょう。Pythonを始め、現在多くのプログラミング言語はオブジェクト指向という考えをを意識して作られています。

オブジェクト指向はベースの考えは、オブジェクトという単位でプログラミングをするということです。つまり「できる限り、オブジェクトというものを頼ってプログラミングをする」ということです。

なぜオブジェクト指向が採用されているかというと

  1. オブジェクトという機能がまとまった単位でプログラムするので、機能の再現性が高い
  2. オブジェクトは内部の状態を保持できるため、外部からのアクセスを制限し機能の書き換えを防ぐため、バグ等に強いプログラムを作成することができる

 

オブジェクト指向の考えでは、「すべてのデータや関数は原則として何かしらの属性をもつ」という規則があります。

オブジェクト指向を学ぶ上で知っておくべ用語があります。

1.2 クラス

クラスは複数の変数や関数の情報をもつものになります。

クラスは抽象的な表現になります。抽象的な表現とは、例えば犬とか猫とか鳥などの固体や実体といったものではなく、”動物”というくくりがクラスになります。

そして、この犬とか猫とか鳥とか、個々の名称がインスタンスになります。

そのため、クラスは複数のインスタンスを含むため、「インスタンス化」と呼ばれます。

 

1.3 インスタンス

クラスが「型」を表すのに対し、インスタンスとはクラスから生成される「実体」と表現され、クラスを基に値やデータ化したものになります。

先程クラスのパートで紹介した通り、インスタンスは実体を表すものになります。

インスタンスは独立したものになるので、必ずクラスに属し属性を持たなければなりません。

 

 

2.ソースコード(クラス・インスタンス)

class Man:
    def __init__(self,name):
        self.name = name
        print("Initialized!")

    def hello(self):
        print("Hello" + self.name + "!")

    def goobye(self):
        print("Good-bye" + self.name + "!")

m = Man("Jon")
m.hello()
m.goodbye()

 

Point 1! : Classは以下のようなフォーマットで定義します。

class クラス名:

def __init__( self ,  引数, …):  #コントラスタ

def メソッド名1(self, 引数, …): #メソッド1

def メソッド名2(self, 引数, …): #メソッド2

 

上記のプログラムは、Manというクラスから、mというインスタンスを生成します。

Manクラスのコンストラクタ(初期メソッド)はnameという引数を取り、その引数でインスタンス変数であるself.nameを初期化します。

インスタンス変数とは個々のインスタンスに格納される変数のこと。

Pythonでは、self.nameのように、selfの後に属性名を書くことでインスタンス変数の作成及びアクセスができます。

 

Point 2 ! コンストラクタとは

コンストラクタ(constructor)とは、__init__という特別なメソッドになります。これは初期化を行うメソッドで必ず最初につけなければなりません。

クラスのインスタンスが生成される際に一度だけ呼ばれるもの

 

Point3 ! 引数selfの役割

Pythonではメソッドの第一引数に自分自身のインスタンスを表すselfを明示的に記述することが特徴です。

上記のコードを例とすると、Man型のインスタンスを用意するときに、ユーザーがどのような変数名を使用するかわかりません。上記のコードでは、mという変数ではなく、もしかしたらNingen、Hitoという変数を指定するかもしれません。そのため、どのような名前でMan型のインスタンスが作られてもいいように、メソッドの第一引数でインスタンスを「self」と呼ぶことが決められているのです。

 

 

3. 継承とは

継承の言葉の意味は引き継ぐという意味がある通り、Pythonにおいてもクラスの継承という部分をよく使用される機能です。

tensorflowなどでこの継承という機能は、よく使用される機能ですので、しっかり押さえておきたい機能ですね。

Point1 継承とは

継承とは、新しいクラスを作るとき、既にあるクラスからメソッドや変数を受け継ぐことができる機能

今回は①継承の具体的な方法、②オーバードライブ、③super()関数を使用した親クラスの継承

の仕方について学習していきたいと思います。

 

今回は皆さんご存じの、ポケモンを題材にクラスの継承を説明していきます。

ちなみに、今回はポケモンの遺伝技として知られるタマゴ技をテーマにクラス継承を学んでいきます。

イメージは以下のような感じです。

画像参照ページ(ピカチュウ):https://www.pokemon.co.jp/ex/sun_moon/pokemon/160920_05.html

画像参照ページ(ピチュー):https://www.pokemon.jp/zukan/detail/172.html

 

3.1 クラス継承(ソースコードと説明)

"""
クラスと継承の話
"""
class Pokemon:
    def __init__(self,name,skill1="10まんボルト",skill2="でんこうせっか"):
        self.name = name
        self.skill1 = skill1
        self.skill2 = skill2

    def waza1(self):
        print(self.name, "の",self.skill1,"!...こうかはばつぐんだ!")

    def waza2(self):
        print(self.name, "の",self.skill2,"...こうかないみたいだ...")

class Pichu(Pokemon):
    pass

pika = Pokemon("ピカチュウ")
print("名前:",pika.name)
print("技1:", pika.skill1)
print("技2:", pika.skill2)
pika.waza1()
pika.waza2()

pichu = Pichu("ピチュー")
print("名前:",pichu.name)
print("技1:", pichu.skill1)
print("技2:", pichu.skill2)
pichu.waza1()
pichu.waza2()

 

今回のコードは、親クラスの定義で、名前とわざ1とわざ2というメソッドを定義し、それを子クラスに継承します。

子クラスの継承は、():丸カッコ内に親クラスを入れてやることで、継承をします。子クラスはメソッドを定義せずpassと定義します。

Point2 クラス継承(コード)

class 子クラス名(親クラス)
  pass #メソッドなど定義

 

この結果を実行してみると

親クラス(ピカチュウ)で定義した名前・わざ1・わざ2のメソッドを子クラス(ピチュー)も引き継いでいます。

 

 

3.2 メソッドのオーバードライブ(ソースコード・説明)

class Pokemon:#親クラスの定義
    def __init__(self,name,skill1="10まんボルト",skill2="でんこうせっか"):
        self.name = name
        self.skill1 = skill1
        self.skill2 = skill2

    def waza1(self):#メソッドの定義1
        print(self.name, "の",self.skill1,"!...こうかはばつぐんだ!")

    def waza2(self):#メソッドの定義2
        print(self.name, "の",self.skill2,"...こうかないみたいだ...")

class Pichu(Pokemon):
    def waza1(self):
        print(self.name, "の",self.skill1,"...ヒットポイントがない!")#メソッド1のオーバードライブ(上書き)

pika = Pokemon("ピカチュウ")
print("名前:",pika.name)
print("技1:", pika.skill1)
print("技2:", pika.skill2)
pika.waza1()
pika.waza2()

pichu = Pichu("ピチュー")
print("名前:",pichu.name)
print("技1:", pichu.skill1)
print("技2:", pichu.skill2)
pichu.waza1()
pichu.waza2()

次にメソッドのオーバードライブについて説明していきます。

3.1で説明した継承では、親クラスで定義したメソッドを全て子クラスに継承しました。

今回は、すべて継承した上で、定義したメソッドを変更する場合、メソッドを上書きして更新していきます。

この親クラスから継承した内容を上書きして変更することをメソッドのオーバードライブといいます。

Point 1 オーバードライブとは

オーバードライブとは、親クラスから継承したメソッドや変数を変更し上書きすることをさす

 

今回の内容では、ピチュー(子クラス)のwaza1というメソッドを変更し上書きしました。

変更前:def waza1(self): print(self.name, “の”,self.skill1,”!…こうかはばつぐんだ!“)

変更後:def waza1(self):  print(self.name, “の”,self.skill1,”…ヒットポイントがない!“)

まずは実行結果を見てみましょう。

実行結果を見てみると、しっかりと上書きされたメソッドが反映されていますね。

ピカチュウでは、10まんボルトをできて、相手のこうかばつぐんをついていますが、ピチューは10まんボルトはヒットポイントがなくて、わざがだせていませんね。

 

 

3.3 super()関数を使用した親クラスの継承(説明・ソースコード)

class Pokemon(object):
    def __init__(self,name,skill1="10まんボルト", skill2="ボルテッカー"):#skill2をNoneと定義
        self.name = name
        self.skill1 = skill1
        self.skill2 = skill2

    def waza1(self):
        print(self.name, "の",self.skill1,"!...こうかはばつぐんだ!")

    def waza2(self):
        print(self.name, "の",self.skill2,"...いちげきひっさつ!!!...")

class Pichu(Pokemon):
    def __init__(self, name,skill1="でんきショック", skill2="でんこうせっか", skill3="あまえる"):
        super(Pichu, self).__init__(name,skill1,skill2)
        self.skill3 = skill3

    def waza3(self):
        print(self.name, "の", self.skill3,"...相手のとくこうががくっと下がった!")#メソッド3の追加

pika = Pokemon("ピカチュウ")
print("名前:",pika.name)
print("技1:", pika.skill1)
print("技2:", pika.skill2)
pika.waza1()
pika.waza2()

pichu = Pichu("ピチュー")
print("名前:",pichu.name)
print("技1:", pichu.skill1)
print("技2:", pichu.skill2)
print("技3:", pichu.skill3)
pichu.waza1()
pichu.waza2()
pichu.waza3()

 

次にsuper()関数を使用して親クラスのメソッドの取得をします。

super()関数は継承元の親クラスを呼び出しつつも、新たにパラメータやメソッドを追加していくことができます。

Point 1 super()関数の役割

子クラスから親クラスを参照し、親クラスのメソッドや変数を呼び出して利用する!

3.2で説明したオーバードライブですが、子クラスで上書きしたメソッドは親クラスのメソッドを上書きしてしまうという欠点もありましたが、

super()関数を使用することで、親クラスのメソッドを変更することなく、子クラスで好きな変数やメソッドを変更・追加することができることもメリットの一つです。

 

ではコードの変更点を見ていきましょう。

変更前:

class Pokemon(object): def __init__(self,name,skill1=”10まんボルト”, skill2=”ボルテッカー”):#skill2をボルテッカーと定義

変更後・追加項目:

class Pichu(Pokemon):  def __init__(self, name,skill1=”でんきショック”, skill2=”でんこうせっか”, skill3=”あまえる”):
super(Pichu, self).__init__(name,skill1,skill2) ←親クラスからを参照し、name・skill1・skill2を変更

self.skill3 = skill3

def waza3(self): print(self.name, “の”, self.skill3,”…相手のとくこうががくっと下がった!”)#メソッド3の追加

 

では実行結果です。

ピカチュウ(親クラス)の技2のでんこうせっかは”ボルテッカー”になっていますね。

さらに、ピチュー(子クラス)では、super()関数で親クラスからメソッドを参照し、skill1・skill2において変更をし、skill3を追加しました。

そのため、出力した結果では、ピチューの技1は”でんきショック”,技2”でんこうせっか”,技3”あまえる”という技名に変更されていますよね。

 

 

4.最後に

今回は、オブジェクト指向で必要なクラス継承の方法やメソッドのオーバードライブ、super()関数の使い方について学習していきました。

オブジェクト指向という考えは、pythonだけでなく多くのプログラミングで利用されているものなので、しっかりと内容だけでもおさえておくことをおススメします。

また、今回はポケモンを題材にクラス継承など説明しました。

自分で学習したコードは、自分の好きな風にコードをアレンジして実行してみると、より理解が深まりますし、自分で作って動いたという感覚も得られるので本当におススメするコーディングの練習方法です。

では、今回は「Python : オブジェクト指向と継承」でした。

これからも基礎編をどんどん掲載していきたいと思います。

コメント

  1. […] オブジェクト指向と継承のまとめ […]

タイトルとURLをコピーしました