3

以下に示すように、Python 3 を使用して抽象クラスを作成しようとしています。

from abc import *


class Base(metaclass=ABCMeta):
    @abstractmethod
    def __init__(self, text=''):
        self._text = text

    @property
    @abstractmethod
    def text(self):
        return self._text

    @text.setter
    @abstractmethod
    def text(self, text):
        self._text = text


class SubClass(Base):

    def __init__(self, text):
        super().__init__(text)

    @property
    def text(self):
        return super().text

q = SubClass("Test")

ファイルを実行すると、インタープリターは text.setter が実装されていないと不平を言いません。エラーが出ないのはなぜですか?

4

1 に答える 1

3

クラス内のtextプロパティの getter と setter はどちらもという名前であるため、セット内で 1 回しか表示されません。でゲッターをオーバーライドすると、セッターもオーバーライドしたかのように「カウント」されます。Basetext__abstractmethods__SubClass

残念ながら、getter のみの抽象化propertyは問題なく機能しますが、抽象化された getter と setter の両方を持つプロパティを持つエレガントな方法は実際にはないようです。単一の名前を使用する場合は、その名前のみをオーバーライドする必要があります (そして、オーバーライドには setter が必要ないことがわかりました)。これらの関数に別の名前を使用してから を使用する場合text = property(_text_get, _text_set)、具象サブクラスは 3 つすべて (getter、setter、およびプロパティ オブジェクト自体) を置き換える必要があります。より良いアプローチは、プロパティ自体をBaseクラス内で具体的にすることですが、抽象化することができ、サブクラスが簡単にオーバーライドできる抽象ゲッターおよびセッター実装関数を呼び出すようにすることです。

@abstractmethod
def _text_get_imp(self):
    return self._text

@abstractmethod
    _text_set_imp(self, value):
    self._text = value

@property
def text(self):
    return self._text_get_imp()

@text.setter
def text(self, value)
    self._text_set_imp(value)

編集: (現在は非推奨) のドキュメントを今日読んだ後abc.abstractproperty、読み取り専用プロパティからエラーが発生しない理由が少しよく理解できたと思います (上記のように単純ではありません)。

エラーが発生しない理由は、新しいプロパティの「設定」の実装が基本クラスとは異なるためです。もちろん、その動作は例外を発生させることですが、技術的には、元のセッターの動作をオーバーライドする別の動作です。

完全にゼロから新しいプロパティを作成するのではなく@Base.text.getter、オーバーライドされたセッター関数のデコレータとして使用して古いプロパティを更新した場合、抽象メソッドがオーバーライドされていないというエラーが発生します。SubClasspropertytext

于 2014-05-02T19:34:04.547 に答える