继承setter,覆盖python抽象类中的getter

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(),这是我不想要的.

我错过了什么?

谢谢!

Bre*_*arn 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
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 要求。