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

5 投票
5 回答
7916 浏览
提问于 2025-04-15 12:33

这个问题和另一个问题有点像,但不同的是,基类中的数据成员并没有被描述符协议包裹起来。

换句话说,如果我在派生类中用一个属性覆盖了基类的成员名,我该如何访问基类的那个成员呢?

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

请注意,我还需要定义一个设置器,因为如果不这样做,基类中的self.foo赋值就无法正常工作。

总的来说,描述符协议似乎和继承的配合不是很好……

5 个回答

1

在编程中,有时候我们会遇到一些问题,比如代码运行不正常或者出现错误。这种情况下,我们需要去寻找解决方案。StackOverflow是一个很好的地方,大家可以在这里提问和回答问题。很多程序员会在这里分享他们的经验和解决办法。

当你在StackOverflow上看到一个问题时,通常会有很多人给出不同的答案。有些答案可能很简单,适合初学者;而有些答案可能比较复杂,需要一定的基础知识才能理解。

如果你遇到的问题在StackOverflow上已经有人提过,你可以直接查看那些答案,看看有没有适合你的解决方法。如果没有,你也可以自己提问,描述清楚你的问题,其他人会尽量帮助你。

总之,StackOverflow是一个学习和解决问题的好地方,适合所有水平的程序员使用。

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
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 )

是的,这样看起来不太“干净”。不过,这样做可以避免在给某个类添加新功能时出现很多问题,就像你现在想做的那样。

3

定义

def __init__(self):
    self.foo = 5

Base 里定义 foo,会让 foo 成为这个实例的一个成员(属性),而不是类的属性。也就是说, Base 并不知道 foo 的存在,所以你不能通过像 super() 这样的调用来访问它。

不过,这其实并不是必须的。当你实例化

foobar = Derived()

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

self.foo = 5

时,这不会导致属性的创建或覆盖,而是会调用 Derived 的设置器,这意味着

self.foo.fset(5)

因此 self._foo = 5。所以如果你在你的获取器里放入

return 1 + self._foo

,你基本上就能得到你想要的结果。如果你需要在 Base 的构造函数中设置的 self.foo 的值,只需查看 _foo,它是通过 @foo.setter 正确设置的。

撰写回答