理解@property装饰器和继承

Raú*_*ado 5 python inheritance super python-3.x

这里是 Python 3,以防万一它很重要。

我试图正确理解如何在@property使用时实现继承,并且我已经搜索了 StackOverflow 并阅读了 20 个类似的问题,但无济于事,因为他们试图解决的问题略有不同。这是我用于测试的代码:

class Example:
    def __init__(self):
        self.__data = None

    @property
    def data(self):
        return self.__data

    @data.setter
    def data(self, data):
        self.__data = data


class Example2(Example):
    def __init__(self):
        super().__init__()

    @property
    def data(self):
        return super().data  # Works!

    @data.setter
    def data(self, data):
        data = '2' + data
        #Example.data = data   # Works, but I want to avoid using the parent name explicitly
        #super().data = data  # Raises AttributeError: 'super' object has no attribute 'data'
        #super().data.fset(self, data) # Raises AttributeError: 'NoneType' object has no attribute 'fset'
        #super(self.__class__, self.__class__).data = data  # Raises AttributeError: 'super' object has no attribute 'data'
        super(self.__class__, self.__class__).data.fset(self, data)  # Works!


a = Example2()
a.data = 'element a'
print(a.data)
Run Code Online (Sandbox Code Playgroud)

我不明白的是为什么super().data在 getter 中有效Example2,但在 setter 中无效。我的意思是,为什么在 setter 中需要类绑定方法,但在 getter 中需要实例绑定方法?

有人可以向我指出解释或解释为什么我会接到AttributeError我正在测试的五个不同呼叫中的三个吗?

是的,我知道,我可以Example.data在 setter 中使用,但这在 getter 中不需要,并且 a) 如果可能的话,我宁愿不显式使用父类名称 b) 我不理解 getter 和 setter 之间的不对称性。

Ser*_*tar 1

你应该这样做:

class Example:
    def __init__(self):
        self._data = None

    @property
    def data(self):
        return self._data

    @data.setter
    def data(self, data):
        self._data = data


class Example2(Example):
    def __init__(self):
        super().__init__()

    @Example.data.setter
    def data(self, data):
        data = '2' + data
        self._data = data


    a = Example2()
    a.data = 'element a'
    print(a.data)
Run Code Online (Sandbox Code Playgroud)

您收到属性错误,因为该类没有数据属性,而实例有它。

如果你想覆盖@property,只需这样做:

class Example:
def __init__(self):
    self._data = None

    @property
    def data(self):
        return self._data

    @data.setter
    def data(self, data):
        self._data = data


class Example2(Example):
    def __init__(self):
    super().__init__()

    @property
    def data(self):
        return self._data

    @data.setter
    def data(self, data):
        data = '2' + data
        self._data = data
Run Code Online (Sandbox Code Playgroud)