PYTHON入門で気をつけるポイント(5)オブジェクト指向についてー(2)

PYTHON入門で気をつけるポイント(5)オブジェクト指向についてー(2)

コンストラクタ

クラスをインスタンス化すると、空のオブジェクトを生成します。
通常オブジェクトを作成する際に、ある特定の初期状態になることが望ましいはずです。
Pythonでは、 __init__() という名前の特別なメソッド定義することができます。
他のプログラムの場合、このような働きのメソッドをコンストラクタと呼びます。

コンストラクタはインスタンスを生成すると自動で実行するメソッドです。
コンストラクタは __init__ という名前をつけて引数には必ずself を第1引数に指定します。

コンストラクタ作成例

class Human:
    def __init__(self, name, age, born):
        self.name = name
        self.age = age
        self.born = born
    
    def talk(self):
        print('私の名前は',self.name,'です。年齢は',self.age,'で',self.born,'生まれです。')
hanako = Human('花子','18','大阪')
hanako.talk()

結果
私の名前は 花子 です。年齢は 18 で 大阪 生まれです。

継承

継承とはクラスが持つ変数とメソッドを引き継いで(継承して)新しいクラスを作る仕組みです。
継承元のクラス:スーパークラス
継承先のクラス:サブクラス

継承の例
サブクラスのインスタンスからもスーパークラスのプロパティsprやメソッドを呼び出せます。

class SuperClass:
    spr = 'スーパー'
    def super_print(self):
        print('スーパークラス')
    
class SubClass(SuperClass):
    def sub_print(self):
        print('サブクラス')

super = SuperClass()
super.super_print()
super.spr

sub = SubClass()
sub.super_print() //これも呼び出せる
sub.sub_print()
sub.spr //これも呼び出せる

結果
スーパークラス
‘スーパー’

スーパークラス
サブクラス
‘スーパー’

class Animal:
  def __init__(self, name):
    self.name = name
  def hello(self):
    print(self.name'は鳴くことができる')
    
class Cat:
  def __init__(self, nema):
    self.name = name
  def hello(self):
    print(self.name'は鳴くことができる')

class Bird:
  def __init__(self, nema):
    self.name = name
  def hello(self):
    print(self.name'は鳴くことができる')


class Crow:
  def __init__(self, nema):
    self.name = name
  def hello(self):
    print(self.name'は鳴くことができる')

class Animal:
  def __init__(self, name):
    self.name = name
  def hello(self):
    print(self.name +'は鳴くことができる')
    
class Bird(Animal):
  def call(self, bow):
    print(bow + 'と鳴く')
    
class Crow(Bird):
  def color(self):
    print(self.name + 'は黒色です')  

class Cat(Animal):
  def run(self):
    print(self.name + 'はジャンプが得意')  

animal = Animal('キョロ')
animal.hello()
bird = Bird('ピーコ')
bird.hello()
crow = Crow('かー子')
crow.hello()
crow.color()
cat = Cat('ニャンコ')
cat.hello()
cat.run()

結果
キョロは鳴くことができる
ピーコは鳴くことができる
かー子は鳴くことができる
かー子は黒色です
ニャンコは鳴くことができる
ニャンコはジャンプが得意

サブ(派生)クラスのメソッド参照

メソッドの参照は次のようにして解決されます。まず対応するクラス属性が検索されます。検索は、必要に応じ、基底クラス連鎖を下って行われ、検索の結果として何らかの関数オブジェクトがもたらされた場合、メソッド参照は有効なものとなります。

継承の特徴

一般的に継承はis-a関係にあると言われます。
is-a関係にない場合には継承でまとめるには向かないと考えると良いでしょう。

is-aの例として、次のようになります。

  • 猿と人は哺乳類の一種。
  • 哺乳類と爬虫類は動物の一種。
  • 動物と植物は生物の一種。

has-aの例としては、次のようになります。

  • 人間は頭、腕、脚、胴体を含んでいる。
  • 腕は上腕、下腕、手を含んでいる。
  • 手は手の甲、手のひら、指を含んでいる。

オーバーライド

スーパークラスとサブクラスで同じ名前のクラスにすると、サブクラスのメソッドがスーパークラスを上書きした状態になります。 このことをオーバーライドと言います。

サブクラスで上書きしているメソッドでは、スーパークラスの同名のメソッドを置き換えるのではなく、拡張することができます。

class Human:
  def hello(self):
    print('Hello')
    
class Japanese(Human):
  def hello(self):
    print('こんにちは')
japanese = Japanese()
japanese.hello()

結果
こんにちは

class Display:
  def __init__(self):
    print('文章を出力できる')
    
  def display(self, sentence):
    print(sentence)
    
class DecoDisplay(Display):
  def display(self, sentence):
    print('〜' + sentence + '〜')

deco = DecoDisplay()
deco.display('sample')

結果
文章を出力できる
〜sample〜

クラスメソッド

クラスメソッドはクラス内で定義されたメソッドで、インスタンス化しなくても呼び出すことができるメソッドです。 また、クラスからもインスタンスからも呼び出すことができます。

クラスメソッドを定義するときは @classmethod デコレーターをつけます。

第1引数が self ではなく cls となっているのに注意

クラスメソッドの例

class Hoge:
  @classmethod
  def foo(cls):
    print('インスタンス化しなくても呼び出せるメソッド')

Hoge().foo()
Hoge.foo()

結果
インスタンス化しなくても呼び出せるメソッド
インスタンス化しなくても呼び出せるメソッド

通常のクラスでクラスメソッドの呼び出しを行っても当然エラーとなる。

class Fuga:
  def foo(self):
    print('インスタンス化しなくても呼び出せるメソッド')

Fuga().foo()
Fuga.foo() #エラーになる

結果
インスタンス化しなくても呼び出せるメソッド
—————————————————————————
TypeError Traceback (most recent call last)
in ()
1 Fuga().foo()
—-> 2 Fuga.foo()

TypeError: foo() missing 1 required positional argument: ‘self’

ポリモーフィズム

ポリモーフィズムとは、どのクラスのオブジェクトかを気にせずにメソッドを使用できるようにするもので、これはオブジェクトの種類を意識しなくてもいいように、オブジェクト間での共通のインターフェースを持たせることです。

実は、演算子の「+」にもポリモーフィズムが利用されています。 数値オブジェクトなら「足し算」を意味するし、文字列なら「連結」を意味しています。 つまりオブジェクトに共通のインターフェースを持たせるが、中身の実装が異なるので振る舞いが変わるものです。

ポリモーフィズムの例

class Dog:
  def cry(self):
    print('ワンワン')

class Cat:
  def cry(self):
    print('ニャーニャー')

class Tiger:
  def cry(self):
    print('ガオー')

def naku(animal):
  animal.cry()

dog = Dog()
cat = Cat()
tiger = Tiger()

naku(dog)
naku(cat)
naku(tiger)


結果
ワンワン
ニャーニャー
ガオー

ポリモーフィズムによる実装を強制する方法として抽象クラスや抽象メソッドを利用します。
抽象(基底)クラス 継承されることを前提としたクラスでインスタンスを作成できない。

抽象メソッドとは実装を持たない、インターフェイスを規定するためのメソッドやクラスに定義できる。
抽象メソッドはサブクラスの中のオーバーライドによって実装されなければいけない

Pythonで抽象クラス、抽象メソッドを利用するには、ABCモジュールを使う 抽象クラスを定義するにはABCクラスを継承し、抽象メソッドを定義するには、@abstractmethodデコータを使用する

from abc import ABC, abstractmethod

class Animal(ABC):
  @abstractmethod
  def cry(self):
    pass

class Dog:
  def cry(self):
    print('ワンワン')

class Cat:
  def cry(self):
    print('ニャーニャー')

class Tiger:
  def cry(self):
    print('ガオー')

tiger = Tiger()
tiger.cry()

結果
ガオー