【问题标题】:Understanding @property decorator and inheritance [duplicate]了解@property 装饰器和继承[重复]
【发布时间】:2016-05-19 08:22:42
【问题描述】:

这里是 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)

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

谁能给我一个解释或解释为什么我在测试的五个不同电话中的三个中得到AttributeError

是的,我知道,我可以在 setter 中使用 Example.data,但在 getter 中不需要这样做,并且 a) 如果可能,我不希望显式使用父类名称,并且 b) 我不明白getter 和 setter 之间的不对称性。

【问题讨论】:

  • 我认为这个问题已经有一段时间了...stackoverflow.com/a/13599342/1345165。显然,唯一的方法是显式使用父类名
  • 你真的不应该在super() 调用中使用self.__class__,请参阅When calling super() in a derived class, can I pass in self.__class__?
  • 您的最后一次调用有效,因为将 类对象 传递给 super() 会为该类生成一个代理,并且访问类上的属性名称会返回原始属性目的。所以super(Example2, Example2).data返回原始属性,所以你可以访问.fset。或者你可以用super(Example2, Example2).__set__(self, new_value)绑定属性。
  • 如果您只想覆盖 getter 或只覆盖 setter 但继承其他属性挂钩,请参阅Python overriding getter without setter
  • @dnaranjo,这个问题是我读到的问题之一,我认为已经解决了。看来我错了。谢谢:)

标签: python python-3.x inheritance super


【解决方案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)

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

如果你想覆盖@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

【讨论】:

  • 但是你正在跳过@property,这是问题的关键
  • 我在实现中编辑了一些错误。如果您正在重新定义 @property,您没有继承任何东西,那么您将覆盖所有内容。有什么意义?该示例也适用于覆盖属性。
  • 谢谢,Serbitar,我知道这个解决方案,但我试图将孩子与父母完全隔离,我的意思是,扩展接口并仅继承接口。我没有在我的 OP 中解释这一点,因为我认为这从代码中很明显,现在我发现它不是。这就是为什么我使用 super() 而不是硬编码父类名的原因。如果我不知道父级设置器的内部结构怎么办?我不知道如何解决这个问题,无论如何我的疑问是为什么 super() 的一种“味道”有效而另一种无效。
猜你喜欢
  • 2014-03-07
  • 2011-03-01
  • 2011-03-23
  • 2018-04-17
  • 2011-09-18
  • 2019-06-10
  • 1970-01-01
  • 2018-09-17
  • 1970-01-01
相关资源
最近更新 更多