如果基类的数据成员被覆盖为派生类中的属性,如何调用它?

时间:2009-06-29 10:03:18

标签: python inheritance overloading descriptor

这个问题类似于this other one,不同之处在于基类中的数据成员包含在描述符协议中。

换句话说,如果我使用派生类中的属性覆盖其名称,我该如何访问基类的成员?

class Base(object):
    def __init__(self):
        self.foo = 5

class Derived(Base):
    def __init__(self):
        Base.__init__(self)

    @property
    def foo(self):
        return 1 + self.foo # doesn't work of course!

    @foo.setter
    def foo(self, f):
        self._foo = f

bar = Base()
print bar.foo

foobar = Derived()
print foobar.foo

请注意,我还需要定义一个setter,否则在基类中分配self.foo不起作用。

总而言之,描述符协议似乎与继承没有良好的交互...

5 个答案:

答案 0 :(得分:9)

如果使用委托而不是继承,生活会更简单。这是Python。您没有义务继承Base

class LooksLikeDerived( object ):
    def __init__( self ):
        self.base= Base()

    @property
    def foo(self):
        return 1 + self.base.foo # always works

    @foo.setter
    def foo(self, f):
        self.base.foo = f

但是Base的其他方法呢?您可以复制LooksLikeDerived中的名称并简单地复制。

def someMethodOfBase( self, *args, **kw ):
    return self.base.someMethodOfBase( *args **kw )

是的,它感觉不到“干”。但是,它可以防止在将某些类“包装”到新功能中时遇到的许多问题,就像您正在尝试的那样。

答案 1 :(得分:4)

定义

def __init__(self):
    self.foo = 5
Base中的

使foo成为实例的成员(属性),而不是类的成员(属性)。 Base不了解foo,因此无法通过super()调用等方式访问它。

然而,这不是必需的。当你实现

foobar = Derived()

并且基类的__init__()方法调用

self.foo = 5

这不会导致创建/覆盖属性,而是调用Derived的setter,意思是

self.foo.fset(5)

因此self._foo = 5。所以,如果你把

return 1 + self._foo
在你的吸气器中,你几乎可以得到你想要的东西。如果您需要在self.foo的构造函数中设置Base的值,请查看由_foo正确设置的@foo.setter

答案 2 :(得分:1)

class Foo(object):
    def __new__(cls, *args, **kw):
        return object.__new__(cls, *args, **kw)

    def __init__(self):
        self.foo = 5

class Bar(Foo):
    def __new__(cls, *args, **kw):
        self = object.__new__(cls, *args, **kw)
        self.__foo = Foo.__new__(Foo)
        return self

    def __init__(self):
        Foo.__init__(self)

    @property
    def foo(self):
        return 1 + self.__foo.foo

    @foo.setter
    def foo(self, foo):
        self.__foo.foo = foo

bar = Bar()
bar.foo = 10
print bar.foo

答案 3 :(得分:0)

一旦你拥有同名“foo”的财产,它就会覆盖名称'foo'的访问行为 唯一的出路似乎是你在 dict

中明确设置'foo'

btw:我使用python 2.5因此不得不稍微更改代码

class Base(object):
    def __init__(self):
        self.foo = 5

class Derived(Base):
    def __init__(self):
        Base.__init__(self)

    def g_foo(self):
        return 1 + self.__dict__['foo'] # works now!

    def s_foo(self, f):
        self.__dict__['foo'] = f
        self._foo = f

    foo = property(g_foo, s_foo)

bar = Base()
print bar.foo

foobar = Derived()
print foobar.foo

答案 4 :(得分:0)

老实说,这里要看的是你试图围绕一个简单的穷人设计扭曲你的代码。属性描述符处理'foo'属性的请求,你想完全绕过这些,这是错误的。你已经导致Base。 init 分配foobar._foo = 5,这也就是getter需要查看的地方。

class Base(object):     def init (个体经营):         self.foo = 5

class Derived(Base):
  def __init__(self):
    Base.__init__(self)

  @property
  def foo(self):
    return 1 + self._foo # DOES work of course!

  @foo.setter
  def foo(self, f):
    self._foo = f

bar = Base()
print bar.foo

foobar = Derived()
print foobar.foo