在子类中访问超类的属性设置器

7

我有一个超类,定义了一个属性及其setter方法,代码如下:

class A(object):
    def __init__(self):
        self._mode = None

    @property
    def mode(self):
        # to be overriden in subclass to implement the actual getter code
        raise NotImplementedError

    @mode.setter
    def mode(self, value):
        # common assertions and input validations
        self._set_mode(value)

    def _set_mode(self, value):
        # to be overriden in subclass to implement the actual setter code
        raise NotImplementedError


class B(A):
    @property
    def mode(self):
        return self._mode

    def _set_mode(self, value):
        self._mode = value


obj = B()
obj.mode = 'test'

这引出了一个问题。
obj.mode = 'test'
AttributeError: can't set attribute

似乎我需要在B中注册一个setter。通常我会这样做:@A.mode.setter,但是这里不适用,因为我实际上并不想在B中定义一个新的setter,而只是重用A中的setter。有人能提供一些解决方法吗?可能很简单,但我现在没有看到:/

1
我突然想到可以添加一个显式的getter方法,像这样,并让mode属性调用此getter return self._mode_getter(),然后重写_mode_getter()。这应该可以工作,但会添加一个可能不需要的方法。 - Emanuel Ey
4个回答

7

getter和setter被存储为property对象的属性(分别作为.fget.fset),因此,当您在子类中重载该属性时,您必须明确提供getter和setter,即:

class B(A):
    @property
    def mode(self):
        return self._mode

    @mode.setter
    def mode(self, value):
        self._mode = value

所以,如果你想让getter和/或setter可以重载而不必重新声明属性,则必须定义一个_get_mode方法,并使属性的getter委托给此方法,就像你为setter所做的一样。
class A(object):
    def __init__(self):
        self._mode = None

    @property
    def mode(self):
        return self._get_mode()

    def _get_mode(self):
        # to be overriden in subclass to implement the actual getter code
        raise NotImplementedError

    @mode.setter
    def mode(self, value):
        # common assertions and input validations
        self._set_mode(value)

    def _set_mode(self, value):
        # to be overriden in subclass to implement the actual setter code
        raise NotImplementedError


class B(A):

    def _get_mode(self):
        return self._mode

    def _set_mode(self, value):
        self._mode = value

3
与在 A 的定义中使用 mode.setter 类似,这个答案 建议使用基类的属性来定义子类的属性,代码如下:
class B(A):
    @A.mode.getter              # only this line is changed!
    def mode(self):
        return self._mode

    def _set_mode(self, value):
        self._mode = value

在这里,mode.setterA 中的相同,但我们已经替换了 getter。


0
一个解决cpython bug的方法是手动从父类获取setter。
ParentClass.some_property.fset(self, value)

例子:

>>> class A:
...     @property
...     def mode(self):
...         return 2
...     
...     @mode.setter
...     def mode(self, value):
...         print("A", value)
... 
>>> class B(A):
...     @property
...     def mode(self):
...         return super().mode + 1
...     
...     @mode.setter
...     def mode(self, value):
...         print("B", value)
...         A.mode.fset(self, value + 1)
... 
>>> a = A()
>>> b = B()
>>> print(f"{a.mode = }")
a.mode = 2
>>> print(f"{b.mode = }")
b.mode = 3
>>> a.mode = 5
A 5
>>> b.mode = 5
B 5
A 6

如果你想让它与父类无关,那么请查看self.__class__.__bases__

0

这种方式对我有效

class A:
    @property
    def mode(self):
        raise NotImplemented
    
    @mode.setter
    def mode(self, value):
        raise NotImplemented

class B(A):
    @A.mode.setter
    def mode(self, value):
        # your setter implement here

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接