サーチ…


ABCMetaメタクラスの設定

抽象クラスは継承されるクラスですが、特定のメソッドの実装は避け、サブクラスが実装する必要があるメソッドシグネチャのみを残します。

抽象クラスは、型定義言語のインタフェースの概念と同様に、メソッドの実装を必要とせずに、クラス抽象を高レベルで定義して強制するのに便利です。

抽象クラスを定義する概念的アプローチの1つは、クラスメソッドをスタブアウトし、アクセスされた場合はNotImplementedErrorを発生させることです。これにより、子クラスが親メソッドに最初にオーバーライドすることなくアクセスすることが防止されます。そのようです:

class Fruit:
    
    def check_ripeness(self):
        raise NotImplementedError("check_ripeness method not implemented!")


class Apple(Fruit):
    pass


a = Apple()
a.check_ripeness() # raises NotImplementedError

このように抽象クラスを作成すると、オーバーライドされていないメソッドが不適切に使用されることがなくなり、子クラスでメソッドを定義することを奨励しますが、定義を強制することはありません。 abcモジュールを使用すると、親クラスと祖先の抽象クラスメソッドをオーバーライドできないときに、子クラスがインスタンス化されるのを防ぐことができます。

from abc import ABCMeta

class AbstractClass(object):
    # the metaclass attribute must always be set as a class variable 
    __metaclass__ = ABCMeta

   # the abstractmethod decorator registers this method as undefined
   @abstractmethod 
   def virtual_method_subclasses_must_define(self):
       # Can be left completely blank, or a base implementation can be provided
       # Note that ordinarily a blank interpretation implicitly returns `None`, 
       # but by registering, this behaviour is no longer enforced.

単純にサブクラス化してオーバーライドすることができます:

class Subclass(AbstractClass):
    def virtual_method_subclasses_must_define(self):
        return

なぜ/ ABCMetaと@abstractmethodの使い方

抽象基本クラス(ABC)は、派生クラスが基本クラスから特定のメソッドを実装することを強制します。

これがどのように機能するのか、なぜそれを使うべきかを理解するために、Van Rossumが楽しめる例を見てみましょう。すべての派生クラスで実装する必要がある2つのメソッド(ジョーク&パンチライン)を持つBaseクラス "MontyPython"があるとしましょう。

class MontyPython:
    def joke(self):
        raise NotImplementedError()

    def punchline(self):
        raise NotImplementedError()

class ArgumentClinic(MontyPython):
    def joke(self):
        return "Hahahahahah"

オブジェクトをインスタンス化して2つのメソッドを呼び出すと、 punchline()メソッドでpunchline()期待どおり)エラーが発生します。

 >>> sketch = ArgumentClinic() 
 >>> sketch.punchline() 
NotImplementedError 

しかし、これにより、エラーを出さずにArgumentClinicクラスのオブジェクトをインスタンス化することができます。実際には、パンチライン()を探すまではエラーは発生しません。

これは、抽象基本クラス(ABC)モジュールを使用することによって回避されます。同じ例でこれがどのように機能するかを見てみましょう:

from abc import ABCMeta, abstractmethod

class MontyPython(metaclass=ABCMeta):
    @abstractmethod
    def joke(self):
        pass

@abstractmethod
def punchline(self):
    pass

class ArgumentClinic(MontyPython):
    def joke(self):
        return "Hahahahahah"

この時点で、不完全なクラスからオブジェクトをインスタンス化しようとすると、すぐにTypeErrorが返されます。

>>> c = ArgumentClinic()
TypeError:
"Can't instantiate abstract class ArgumentClinic with abstract methods punchline"

この場合、クラスを完成させてTypeErrorsを回避するのは簡単です:

class ArgumentClinic(MontyPython):
    def joke(self):
        return "Hahahahahah"

    def punchline(self):
        return "Send in the constable!"

今度はオブジェクトをインスタンス化するときに動作します!



Modified text is an extract of the original Stack Overflow Documentation
ライセンスを受けた CC BY-SA 3.0
所属していない Stack Overflow