Python 抽象クラス

Python学習【365日チャレンジ!】84日目のマスターU(@Udemy11)です。

前にちらっとチャーシューを作った話をしましたが、実は料理好きなんです。

といってもたまにしか料理はしませんが、包丁にはこだわって、吉田金属工業のGlobalを使っています。

といっても、結構な値段がするので、1本しか持ってないんですけどね。。。

ホームベーカリーも持っていて、たまにパンを焼くので、今一番欲しいものは、Globalのパン切り包丁なんですが、「切れ味が悪くなったらどうやって研ぐんだろう?」と勝手に心配しています。

それではさっそくPython学習をはじめましょう!

昨日の復習

昨日は、ダックタイピングについて学習しました。

ダックタイピングは、クラスが違っても、同じ名前のメソッドがあれば、オブジェクトを切り替えて使えるということでした。

class Animal:
    def voice(self, animal):
        animal.voice()

class Duck:
    def voice(self):
        print('quack quack')

class Dog:
    def voice(self):
        print('Bow Bow')

duck = Duck()
dog = Dog()
mascot = Animal()

mascot.voice(duck)
mascot.voice(dog)

出力結果

quack quack
Bow Bow

昨日学習したコードとは違うコードを使ってみましたが、Animalクラスから生成されたmascotのメソッドであるvoiceの引数を変数animalにしているので、17行目のmascot.voice(duck)は、変数animal = duckになり、duck.voice()を実行することになります。

18行目も同様に、dog.voice()を実行することになるので、アヒルの鳴き声と犬の鳴き声が出力されているということです。

このパターンでは、DuckクラスでもDogクラスでもvoiceメソッドが存在して、生成されたオブジェクトduckdogを切り替えて、voiceメソッドを利用することができるということです。

詳しくは昨日の記事を参考にしてみてください。

それでは、本日の学習をすすめていきましょう!

抽象クラス

抽象クラスは、複数の継承クラスで同じメソッドを書く必要があるときに、ベース(親)クラスに「きちんとこのメソッドは継承クラスに入れてくださいね。入れないとエラーになりますよ」と記述しているクラスになります。

例えば、昨日学習したコードが次になりますが、ベースクラスでdriveメソッドを指定しているので、継承クラスはそのdriveメソッドを継承しています。

class Person(object):
    def __init__(self, age=1):
        self.age = age

    def drive(self):
        if self.age >= 18:
            print("Yes! You can do it.")
        else:
            print("No! You can't drive.")

class Kids(Person):
    def __init__(self, age=1):
        if age < 18:
            super().__init__(age)
        else:
            raise ValueError

class Adult(Person):
    def __init__(self, age=18):
        if age >= 18:
            super().__init__(age)
        else:
            raise ValueError

ベースクラスのdriveメソッドを切り分けて、次のように継承クラスに記述することもできます。

class Person(object):
    def __init__(self, age=1):
        self.age = age

class Kids(Person):
    def __init__(self, age=1):
        if age < 18:
            super().__init__(age)
        else:
            raise ValueError

    def drive(self):
        print("No! You can't drive.")

class Adult(Person):
    def __init__(self, age=18):
        if age >= 18:
            super().__init__(age)
        else:
            raise ValueError

    def drive(self):
        print("Yes! You can drive.")

この場合、Personを継承するクラスに必ずdriveメソッドを記述する必要があるので、記述を忘れるとエラーが起こってしまいます。

そのため、継承クラスがdriveメソッドの記述がない場合にエラーを返すベースクラスを作ることができ、それが抽象クラスということです。

抽象クラスの記述方法

抽象クラスの記述方法は次のとおり

import abc

class Person(metaclass=abc.ABCMeta):
    def __init__(self, age=1):
        self.age = age

    @abc.abstractmethod
    def drive(self):
        pass

コードが長くなるので、ベースクラスだけを抽出して記述しています。

@abc.abstractmethodを使うことで、継承クラスのインスタンスを生成する際に、指定したメソッドが記述(実装)されていない場合はエラーが起こります。

一方で、抽象クラスを使わずに、継承クラスにメソッドが実装されていない場合は、インスタンスを生成する際にはエラーにならずに、メソッドを呼び出す際にエラーになります。

どの時点でエラーを返すかの違いで、基本にはどちらもエラーになるので、個人的にはあまり使う必要がないんじゃないかと思っちゃいました。

基本的にあまり使われない

Pythonはもともとこの抽象クラスという概念がなかったらしく、Javaで実行されていたので、アップデートの際にabcモジュールとして標準ライブラリに加えられたという経緯があるとのことです。

なので、特に使う必要がないのなら、使わなくても問題なく、対応しなくても構わないというのが暗黙のルールでもあるようです。

複数人での開発がベース

最近になって気づいたのですが、このあたりの酒井さんの講座は、複数人でプログラムを書くことを前提の内容になっているので、一人で開発をすすめるにあたっては、ちょっと違和感を感じる部分があります。

つまり、わざわざそんなことする必要あるのかな?と思っちゃうわけです。

今後、自分のパッケージを配布するようになったり、チームでプログラムを書くようになった場合は、役立つスキルになるとは思うので、複数人で開発するための内容であると認識して学習しようと考えています。

酒井さんのPython講座は、Pythonの基礎基本から実践までを幅広く学びたい人には、おすすめの講座に間違いはありませんので、ぜひ一度受講されることをおすすめします。

Udemy講師 酒井さん プログラミング Python

それでは、明日もGood Python!