如何在派生类中调用被覆盖为属性的基类数据成员?
这个问题和另一个问题有点像,但不同的是,基类中的数据成员并没有被描述符协议包裹起来。
换句话说,如果我在派生类中用一个属性覆盖了基类的成员名,我该如何访问基类的那个成员呢?
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 个回答
在编程中,有时候我们会遇到一些问题,比如代码运行不正常或者出现错误。这种情况下,我们需要去寻找解决方案。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
如果你使用委托而不是继承,生活会简单很多。这是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 )
是的,这样看起来不太“干净”。不过,这样做可以避免在给某个类添加新功能时出现很多问题,就像你现在想做的那样。
定义
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
正确设置的。