Sea*_*ice 5 python inheritance properties abc
假设您在基类中具有一个属性,该属性具有setter
将在所有子类中使用的单个方法,但在所有子类中使用不同的getter
方法.理想情况下,您只想setter
在基类中编写一次该方法的代码.此外,您希望使基类抽象,因为它没有完整的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()
Run Code Online (Sandbox Code Playgroud)
但upper = uppercase()
失败了Can't instantiate abstract class uppercase with abstract methods str
.
如果我将@abc.abstractproperty
课程内容更改_mystring
为@property
,则upper = uppercase()
可以正常工作,但也可以upper = _mystring()
,这是我不想要的.
我错过了什么?
谢谢!
我设法做了一个小包装来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
Run Code Online (Sandbox Code Playgroud)
然后你的代码只需稍加修改即可工作:
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()
Run Code Online (Sandbox Code Playgroud)
然后行为如预期:
>>> _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'
Run Code Online (Sandbox Code Playgroud)
我的partialAP
包装器必须与 结合使用abc.abstractmethod
。你所做的就是用它abstractmethod
来装饰你想要抽象的属性的“部分”(getter 或 setter),并用作partialAP
第二个装饰器。 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)
Run Code Online (Sandbox Code Playgroud)
然后它就起作用了:
>>> _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'
Run Code Online (Sandbox Code Playgroud)
诀窍是你不能使用方便的装饰器。装饰abstractproperty
器将整个属性标记为抽象的。您所要做的就是创建两个方法,一个抽象方法(用于 getter)和一个常规方法(用于 setter),然后创建一个组合它们的常规属性。然后,当您扩展该类时,必须重写抽象 getter 并显式地将其与基类属性“混合”(使用_mystring.str.getter
)。
不能使用的原因@_mystring.str.getter
是装饰器强制 getter 和 setter 与属性本身具有相同的名称。如果您只想将两者之一标记为抽象,则它们必须具有不同的名称,否则您无法单独获取它们。
请注意,此解决方案要求子类为它们的 getter 提供正确的名称(_strGet
在本例中),以满足它们重写抽象方法的 ABC 要求。
归档时间: |
|
查看次数: |
1137 次 |
最近记录: |