5

すべてのサブクラスで使用される単一のメソッドを持つ基本クラスに属性があるとしますがsetter、すべてのサブクラスで異なるgetterメソッドを使用します。理想的には、setterメソッドのコードを基本クラスで 1 回だけ記述します。getterさらに、完全なメソッドがないため、基本クラスを抽象化する必要があります。これを行う方法はありますか?

素朴に、私はそれが次のようになるべきだと思います:

class _mystring(object):

    __metaclass__ = abc.ABCMeta

    @abc.abstractproperty
    def str(self):
        pass

    @str.setter
    def str(self,value):
        self._str = value

class uppercase(_mystring):

    @_mystring.str.getter
    def str(self):
        return self._str.upper()

しかし、upper = uppercase()で失敗しCan't instantiate abstract class uppercase with abstract methods strます。

@abc.abstractpropertyin クラス_mystring@propertyに変更するとupper = uppercase()動作しますが、 も動作しupper = _mystring()ます。これは望ましくありません。

私は何が欠けていますか?

ありがとう!

4

1 に答える 1

3

私はそれを行う小さなラッパーを作るabstractpropertyことができました:

class partialAP(abc.abstractproperty):
    def getter(self, func):
        if getattr(func, '__isabstractmethod__', False) or getattr(self.fset, '__isabstractmethod__', False):
            p = partialAP(func, self.fset)
        else:
            p = property(func, self.fset)
        return p

    def setter(self, func):
        if getattr(self.fget, '__isabstractmethod__', False) or getattr(func, '__isabstractmethod__', False):
            p = partialAP(self.fget, func)
        else:
            p = property(self.fset, func)
        return p

次に、コードをわずかに変更するだけで機能します。

class _mystring(object):

    __metaclass__ = abc.ABCMeta

    @partialAP
    @abc.abstractmethod
    def str(self):
        pass

    @str.setter
    def str(self,value):
        self._str = value

class uppercase(_mystring):

    @_mystring.str.getter
    def str(self):
        return self._str.upper()

そして、動作は必要に応じて次のようになります。

>>> _mystring()
Traceback (most recent call last):
  File "<pyshell#3>", line 1, in <module>
    _mystring()
TypeError: Can't instantiate abstract class _mystring with abstract methods str
>>> u = uppercase()
>>> u.str = 'a'
>>> u.str
'A'

私のpartialAPラッパーは と組み合わせて使用​​する必要がありますabc.abstractmethod。あなたがすることはabstractmethod、抽象化したいプロパティ (ゲッターまたはセッター) の「ピース」を装飾するために使用partialAPし、2 番目のデコレーターとして使用することです。 partialAPgetter と setter の両方が非抽象である場合にのみ、プロパティを通常のプロパティに置き換える getter/setter 関数を定義します。

明らかに、これを少し拡張して、プロパティ デリータでも価値があるようにする必要があります。より複雑な継承階層がある場合、正しく処理されないまれなケースもある可能性があります。

後世のための古い解決策:

class _mystring(object):

    __metaclass__ = abc.ABCMeta

    @abc.abstractmethod
    def _strGet(self):
        pass

    def _strSet(self,value):
        self._str = value

    str = property(_strGet, _strSet)

class uppercase(_mystring):

    def _strGet(self):
        return self._str.upper()
    str = _mystring.str.getter(_strGet)

それは動作します:

>>> _mystring()
Traceback (most recent call last):
  File "<pyshell#39>", line 1, in <module>
    _mystring()
TypeError: Can't instantiate abstract class _mystring with abstract methods _strGet
>>> u = uppercase()
>>> u.str = 'a'
>>> u.str
'A'

秘訣は、便利なデコレータを使用しないことです。abstractpropertyデコレーターは、プロパティ全体を抽象としてマークします。必要なのは、抽象メソッド (getter 用) と通常のメソッド (setter 用) の 2 つのメソッドを作成し、それらを組み合わせた通常のプロパティを作成することです。次に、クラスを拡張するときに、抽象ゲッターをオーバーライドし、それを基本クラスのプロパティと明示的に「混合」する必要があります ( を使用_mystring.str.getter)。

使用できない理由@_mystring.str.getterは、デコレーターが getter と setter の両方にプロパティ自体と同じ名前を強制するためです。2つのうちの1つだけを抽象としてマークしたい場合は、それらに異なる名前を付ける必要があります。そうしないと、それらを個別に取得できません。

このソリューションでは_strGet、抽象メソッドをオーバーライドしたという ABC を満たすために、サブクラスがゲッターに正しい名前 (この場合) を付ける必要があることに注意してください。

于 2013-10-31T21:24:05.593 に答える