Pythonでの継承、抽象基本クラスおよびインターフェース

継承、抽象基本クラス、Pythonのインターフェイスの関係を1文に要約します。Pythonのインターフェイスメカニズムは抽象基本クラスを通じて実現できインターフェイス実現は継承メカニズムに依存します

1.継承

継承は、オブジェクト指向プログラミング言語の3つの特性の1つです(他の2つは、カプセル化ポリモーフィズムです)。いわゆる継承とは、サブクラスが自動的に親クラスによって定義されたメソッドと属性を持ち、サブクラスが同じ名前のメソッドを繰り返し定義する必要がないことを意味します。または属性です。継承の最大の利点の1つは、コードの再利用の度合いを改善できることです。

1.一般的なシリーズの場合

ここでは、Pythonの継承の概念を紹介します。これは、高校の数学における重要な概念である数値のシーケンスです。シーケンスは、一連の値で構成されるシーケンスです。シーケンスの各値は、シーケンス内の前のアイテムまたは複数のアイテムによって異なります。次に例を示します。

  • 算術シーケンスの場合、シーケンスの2番目の項目から始まり、各項目は前の項目に固定定数を追加することによって取得されます。
  • 幾何学的シーケンスの場合、シーケンスの2番目の項から開始して、各項は前の項に固定定数を乗算することによって取得されます。
  • フィボナッチシーケンスの場合、シーケンスの3番目のアイテムから始まり、各アイテムには最初の2つのアイテムの合計があります。

オブジェクト指向の機能を使用して、上記の異なるタイプのシリーズのコードを抽象化する必要がある場合、3つのシリーズのシリーズは、類似の機能を持つ以下のメソッドをサポートする必要があると想像できます。

  • 初期化メソッド:シーケンスの最初の数項目を初期化するために使用されます。
  • 走査サポート方法:反復可能な方法でシーケンスの項目の走査をサポートできます。
  • シーケンスアイテムの生成方法:特定のルールに従って、最初のいくつかのアイテムに従って任意のアイテムを生成します。

継承の方法が採用されていない場合、各シーケンスクラスの最終的な実現は、高度なコードの繰り返しになります。

2.一般的なシーケンスの実現

上記の議論に対応して、継承を使用して各シーケンスクラスを実装することを検討してください。

  • まず、一般的なシーケンスの親クラスを定義Progressionします。このシーケンスでは、シーケンスの一般的なメソッドと実用的なメソッドが実現されます。
  • 次に、継承されたProgressionクラスは、親クラスメソッドを書き換えるか、シーケンスの一般的な用語の生成規則に従って、算術、等比、およびフィボナッチシーケンスで新しいメソッドを定義します。

基本クラス

シーケンス基本クラスでは:

  • __init__初期化メソッドはstart、シーケンスの最初の項目の値を指定するため、およびnumデフォルトで印刷されるシーケンス項目の数を指定するために2つのパラメーター受け取ります。これらはそれぞれ_current合計_numを初期化するために使用されます
  • _advanceこのメソッドは、番号シーケンスの一般的なルールに従ってアイテムを生成するために使用されます。
  • __iter__また、__next__メソッドは、Pythonの反復子プロトコルをサポートするために使用されます(詳細については、Pythonのforループ操作メカニズムの探索と反復可能なオブジェクトと反復子の詳細な説明を参照してください)。
  • __str__このメソッドは、シーケンスオブジェクトをリストに変換し、リストの文字列表現を返すために使用されます。
class Progression:
    """数列基类"""

    def __init__(self, start=0, num=10):
        """
        将当前数列的第一项初始化为0
        :param start: 数列第一项,默认为0
        :param num: 打印数列时的默认显示项数
        """
        self._current = start
        self._num = num

    def _advance(self):
        """用于根据数列前若干项进行任意项的生成,该方法应该被子类重写"""
        self._current += 1

    def __next__(self):
        """迭代器协议方法,返回数列中的下一项,当已至数列最后一项则抛出StopIteration异常"""
        if self._num > 0:
            ans = self._current
            self._advance()
            self._num -= 1
            return ans
        else:
            raise StopIteration

    def __iter__(self):
        """迭代器协议方法,返回对象自身"""
        return self

    def __str__(self):
        """返回对象的字符串表示形式"""
        return str(list(self))

算術シーケンス

継承されたProgressionクラスによる算術シーケンスの実現では、次のようになります。

  • __init__このメソッドでは、親クラス初期化メソッドが呼び出され、親クラスから継承_currentされ、デフォルト_numで出力されるシーケンス項目の数を初期化しこのクラスに固有の算術シーケンス定数も初期化し_incrementます。
  • _advanceこのメソッドは、算術シーケンスの一般的な規則に従って、同じ名前の親メソッドを書き換えます。
  • __next____iter__そして__str__メソッドはProgressionクラスから継承され、コードを書き直す必要はありません。
class ArithmeticProgression(Progression):
    """等差数列"""

    def __init__(self, start=0, increment=1, num=10):
        """
        创建一个新的等差数列
        :param increment: 等差常量,默认为1
        :param start: 数列首项,默认为0
        :param num: 打印数列时的默认显示项数
        """
        super().__init__(start=start, num=num)
        self._increment = increment

    def _advance(self):  # 重写父类同名方法
        """根据等差数列通项规则,生成任意项"""
        self._current += self._increment

幾何学的シーケンス

継承されたProgressionクラスのため、幾何学的シーケンスの実現では、次のようになります。

  • __init__このメソッドでは、親クラス初期化メソッドが呼び出されて、親クラスから継承_currentされ、デフォルト_numで出力されるシーケンス項目の数を初期化しこのクラスに固有の幾何学的シーケンス定数も初期化し_baseます。
  • _advanceこのメソッドは、ジオメトリックシーケンスの一般的なルールに従って、親クラスの同じ名前のメソッドを書き換えます。
  • __next____iter__そして__str__メソッドはProgressionクラスから継承され、コードを書き直す必要はありません。
class GeometricProgression(Progression):
    """等比数列"""

    def __init__(self, start=1, num=10, base=2):
        """
        创建一个新的等比数列
        :param base: 等比常量,默认值为2
        :param start: 数列首项,默认为1
        :param num: 打印数列时的默认显示项数
        """
        super().__init__(start=start, num=num)
        self._base = base

    def _advance(self):
        """根据等比数列通项规则,生成任意项"""
        self._current *= self._base

フィボナッチ数列

フィボナッチ数列の実現では、Progressionクラスを継承するため、次のようになります。

  • __init__親クラスの初期化メソッドは、親クラスから継承_currentされ、デフォルト_numで出力されるシーケンスアイテムの数を初期化するメソッドで呼び出され、クラスに固有の仮想アイテム0も初期化し_prevます。
  • _advanceこのメソッドは、フィボナッチ数列の一般的な規則に従って、親クラスの同じ名前のメソッドを書き換えます。
  • __next____iter__そして__str__メソッドはProgressionクラスから継承され、コードを書き直す必要はありません。
class FibonacciProgression(Progression):
    """斐波那契数列"""

    def __init__(self, first=0, second=1, num=10):
        """
        创建一个新的斐波那契数列
        :param first: 数列第一项,默认为0
        :param second: 数列第二项,默认为1
        :param num: 打印数列时的默认显示项数
        """
        super().__init__(start=first, num=num)
        self._prev = second - first  # 假想在第一项之前存在的第零项

    def _advance(self):
        """根据斐波那契数列通项规则,生成任意项"""
        self._prev, self._current = self._current, self._prev + self._current

以下は、上記の一連の実現クラスのテスト結果です。

if __name__ == '__main__':
    print('默认数列Progression:')
    print(Progression(num=5), end='\n'*2)  # [0, 1, 2, 3, 4]
    
    print('等差数列ArithmeticProgression:')
    print(ArithmeticProgression(start=10, increment=3, num=7), end='\n'*2)  # [10, 13, 16, 19, 22, 25, 28]
    
    print('等比数列GeometricProgression:')
    print(GeometricProgression(start=4, base=3, num=9), end='\n'*2)  # [4, 12, 36, 108, 324, 972, 2916, 8748, 26244]
    
    print('斐波那契数列FibonacciProgression:')
    print(FibonacciProgression(first=2, num=12))  # [2, 1, 3, 4, 7, 11, 18, 29, 47, 76, 123, 199]

2、抽象基本クラス

上記のコードを注意深く分析すると、基本クラスProgressionArithmeticProgressionGeometricProgressionおよび基本クラスはとして意図さFibonacciProgressionれていますが、インスタンス化によってProgressionオブジェクトが提供されますが、これはArithmeticProgression特別なケースにすぎないため、あまり重要ではありません。つまり、最初の項は0です。算術定数が1の算術シーケンス。

オブジェクト指向プログラミングパラダイムをサポートする言語でProgressionは、このクラスには、複数のサブクラスが実装する必要があるメソッドを指定するために基本クラスとしてのみ使用される特別な用語があります抽象基本クラス

Python3で抽象基本クラスを定義する場合は、次の手順で行うことできます。

  • 抽象基本クラスを定義する前に、モジュールからabcクラスABCMetaとメソッドインポートしますabstractmethod
  • 抽象基本クラスを定義する場合
    • 抽象基本クラス名の後に指定metaclassABCMetaます。
    • これは抽象基本クラスがサブクラスによって継承される必要があるメソッド(一般に抽象メソッドと呼ばれます)の前に使用され@abstractmethodます。

例:前述のように、Progressionメソッドの場合、上記のプロセスに従ってそれを抽象基本クラスとして定義するコードは次のとおりです。

from abc import ABCMeta, abstractmethod


class Progression(metaclass=ABCMeta):
    """数列基类"""

    def __init__(self, start=0, num=10):
        """
        将当前数列的第一项初始化为0
        :param start: 数列第一项,默认为0
        :param num: 打印数列时的默认显示项数
        """
        self._current = start
        self._num = num

    @abstractmethod
    def _advance(self):
        """用于根据数列前若干项进行任意项的生成,该方法应该被子类重写"""

    def __next__(self):
        """迭代器协议方法,返回数列中的下一项,当已至数列最后一项则抛出StopIteration异常"""
        if self._num > 0:
            ans = self._current
            self._advance()
            self._num -= 1
            return ans
        else:
            raise StopIteration

    def __iter__(self):
        """迭代器协议方法,返回对象自身"""
        return self

    def __str__(self):
        """返回对象的字符串表示形式"""
        return str(list(self))

上記のコード抽象メソッド_advance定義することがわかります。これは、一方でこのメソッドがすべてのサブクラスに存在する必要があり、他方で、すべてのサブクラスでのこのメソッドの実装が完全に異なるためです。

のために、ことに留意すべきである抽象基底クラス(例えばProgression、それ以外の場合は、このようなエラーを報告します、それは直接オブジェクトを作成することにより、インスタンス化することはできません): TypeError: Can't instantiate abstract class Progression with abstract methods _advance

3、インターフェース

インターフェイスは、さまざまなコード作成者が次のことを実行できるようにするプログラミングメカニズムです。

  • 同じコードシグネチャ(メソッド名(_advance)、パラメーター、戻り値など)に従います。
  • 算術、幾何比、フィボナッチ数列の一般的な用語に基づいてルールを生成する_advance方法など、さまざまなアルゴリズムを使用して特定のコードを実装します

インターフェイスメカニズムの利点は、次のことができることです。

  • たとえば、アプリケーションアーキテクトは全体的なフレームワークを構築し、特定の実装は実装スタッフに任せることができます。これは、上司が一般的に手元のリソースに基づいて特定のことを行うように指示しているようです物事と期待される結果とは何か、そしてあなたとあなたの同僚は、特定のプロセスを通じて各物事を実装するために一生懸命取り組む必要があります。
  • コード間の疎結合を実現するために、各インターフェイスの実装担当者は、他の担当者によるインターフェイスの内部固有の実装を知る必要はありません。

Pythonでは、サブクラスが抽象基本クラスを継承し、その中のすべての抽象メソッドを実装する限り、インターフェイスの特定の実装

以下は、インターフェース実装プロセスを示すための上記のシーケンスクラスの例です。

from abc import ABCMeta, abstractmethod


class Progression(metaclass=ABCMeta):
    """数列基类"""

    def __init__(self, start=0, num=10):
        """
        将当前数列的第一项初始化为0
        :param start: 数列第一项,默认为0
        :param num: 打印数列时的默认显示项数
        """
        self._current = start
        self._num = num

    @abstractmethod
    def _advance(self):
        """用于根据数列前若干项进行任意项的生成,该方法应该被子类重写"""

    def __next__(self):
        """迭代器协议方法,返回数列中的下一项,当已至数列最后一项则抛出StopIteration异常"""
        if self._num > 0:
            ans = self._current
            self._advance()
            self._num -= 1
            return ans
        else:
            raise StopIteration

    def __iter__(self):
        """迭代器协议方法,返回对象自身"""
        return self

    def __str__(self):
        """返回对象的字符串表示形式"""
        return str(list(self))


class FibonacciProgression(Progression):
    """斐波那契数列"""

    def __init__(self, first=0, num=10, second=1):
        """
        创建一个新的斐波那契数列
        :param first: 数列第一项,默认为0
        :param second: 数列第二项,默认为1
        :param num: 打印数列时的默认显示项数
        """
        super().__init__(start=first, num=num)
        self._prev = second - first  # 假想在第一项之前存在的第零项

    def _advance(self):
        """根据斐波那契数列通项规则,生成任意项"""
        self._prev, self._current = self._current, self._prev + self._current


if __name__ == '__main__':

    print(FibonacciProgression(first=2, num=12))  # [2, 1, 3, 4, 7, 11, 18, 29, 47, 76, 123, 199]

おすすめ

転載: blog.csdn.net/weixin_37780776/article/details/108372236