5

这个问题与另一个问题类似,不同之处在于基类中的数据成员没有被描述符协议包装。

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

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 的分配不起作用。

总而言之,描述符协议似乎不能与继承很好地交互......

4

5 回答 5

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 )

是的,它不会感觉“干燥”。但是,当您尝试将某些类“包装”在新功能中时,它可以防止很多问题。

于 2009-06-29T10:41:40.373 回答
4

定义

def __init__(self):
    self.foo = 5

inBase创建实例foo的成员(属性),而不是类的成员。该类不了解,因此无法通过调用之类的方式访问它。 Basefoosuper()

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

foobar = Derived()

以及__init__()基类调用的方法

self.foo = 5

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

self.foo.fset(5)

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

return 1 + self._foo

在你的吸气剂中,你几乎得到了你想要的。如果您需要self.foo在 的构造函数中设置的值Base,只需查看_foo@foo.setter.

于 2009-06-29T10:24:25.773 回答
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
于 2009-06-29T13:13:45.073 回答
0

一旦您拥有具有相同名称“foo”的属性,它就会覆盖名称“foo”的访问行为,唯一的出路似乎是您在dict中明确设置了“foo”

顺便说一句:我使用 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
于 2009-06-29T10:25:12.153 回答
0

老实说,这里要看的是你正试图围绕一个糟糕的设计扭曲你的代码。属性描述符处理对“foo”属性的请求,而您想完全绕过这些,这是错误的。你已经在造成 Base. init分配 foobar._foo = 5,所以这也正是 getter 需要查看的地方。

类 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 # DOES work of course!

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

bar = Base()
print bar.foo

foobar = Derived()
print foobar.foo
于 2009-06-29T23:31:53.780 回答