私はそれを行う小さなラッパーを作る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 番目のデコレーターとして使用することです。 partialAP
getter と 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 を満たすために、サブクラスがゲッターに正しい名前 (この場合) を付ける必要があることに注意してください。