【问题标题】:How do I override a field in a base class with a property in a derived class?如何使用派生类中的属性覆盖基类中的字段?
【发布时间】:2013-05-16 01:41:35
【问题描述】:

我有一个使用字段的基类:

class Base(object):
    def __init__(self, member):
        self.member = member

还有一个派生类希望将其提升为属性,并添加一些行为:

class Derived(Base):
    @property
    def member(self):
        return super(Derived, self).member

    @member.setter
    def member(self, value):
        print "intercepting setter"
        super(Derived, self).member = value

但是,这并没有正确地委托给基类:

>>> d = Derived(0)
intercepting setter

Traceback (most recent call last):
  File "<pyshell#8>", line 1, in <module>
    d = Derived(0)
  File "<pyshell#3>", line 3, in __init__
    self.member = 2
  File "<pyshell#6>", line 9, in member
    super(Derived, self).member = value
AttributeError: 'super' object has no attribute 'member'

我应该怎么做?

【问题讨论】:

    标签: python properties overriding


    【解决方案1】:

    您正在尝试访问超级的member,就好像它是一个类属性一样。尝试:

    class Derived(Base):
        @property
        def member(self):
            print "intercepting getter"
            return self._member
    
        @member.setter
        def member(self, value):
            print "intercepting setter"
            self._member = value
    

    【讨论】:

    • 我刚刚明白你的答案就是我最终的答案。
    • “好像它是一个类属性” - 那不是显示为super(Derived).member吗?
    • 不,super 的使用不会让您访问Base 的假设member 属性(您需要一个绑定的超级对象,提供这样的实例: super(Derived, self).member)。无论如何,在您的代码中,member 是在构造函数中初始化的 instance 属性super 用于访问来自基类的内容,而不是来自类实例的内容。
    • 我想我的错误是假设“基本实例属性”和“派生实例属性”之间存在区别
    【解决方案2】:

    我认为提升一个成员到一个属性是正确的做法。这就像在基类中有一个int 成员并将其更改为派生类中的一个方法。或者像拥有一个普通方法并将其更改为继承者中的静态或类方法。我想这只是打破了这个概念。

    您有多种选择来解决问题。

    我。如何引入一个不同(相似)名称的属性,然后将所有访问权限传递给继承的原始名称?这将非常简单,不会破坏从基类继承的任何内容。但它也不允许拦截对原始成员的访问(在基类或任何地方完成)。

    二。完全替换继承的成员。这只是意味着将值存储在不同的成员中并完全从头开始创建属性。稍后再让它访问原来的store:

    class Base(object):
    
        def __init__(self, member):
            self.member = member
    
        def baseAccess(self):
            return self.member
    
    class Derived(Base):
        @property
        def member(self):
            print "getter",
            return self.memberStore
    
        @member.setter
        def member(self, value):
            print "setter",
            self.memberStore = value
    
    b = Base(24)
    print "Base(24)"
    print "b.member", b.member
    print "b.baseAccess()", b.baseAccess()
    d = Derived(23)
    print "Derived(23)"
    print "d.member", d.member
    print "d.baseAccess()", d.baseAccess()
    
    b.member = 43
    print "b.member = 43"
    print "b.member", b.member
    print "b.baseAccess()", b.baseAccess()
    d.member = 42
    print "d.member = 42"
    print "d.member", d.member
    print "d.baseAccess()", d.baseAccess()
    

    这是输出:

    Base(24)
    b.member 24
    b.baseAccess() 24
    setter getter Derived(23)
    d.member getter 23
    d.baseAccess() getter 23
    b.member = 43
    b.member 43
    b.baseAccess() 43
    setter d.member = 42
    d.member getter 42
    d.baseAccess() getter 42
    

    所以所有的拦截器都得到了适当的考虑。

    【讨论】:

    • 肯定self.memberStore = self.member 是没有操作的,因为self.member 返回self.memberStore?
    • 你是对的!那条线是没有必要的。我删除它。然后整个__init__() 就不再需要了。也删除它。
    • 另外,.baseAccess() 似乎在进行派生访问,因为它会触发拦截器
    • 在派生类的实例中,是的。不在基类的实例中。我想这就是人们想要的,不是吗?
    • 我想我的意思是self.member 不只是由b.baseAccess() 代理
    猜你喜欢
    • 2017-07-05
    • 1970-01-01
    • 2010-11-04
    • 2021-08-31
    • 1970-01-01
    • 1970-01-01
    • 2022-12-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多