2009-06-29 34 views
5

此问题与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的赋值不起作用。

总而言之描述符协议似乎并没有与继承以及互动......

回答

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 

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

+0

所有的答案都非常有趣,我upvoted大部分,但这次是直接到这一点,它真的让我明白了手头的问题。 – UncleZeiv 2009-06-30 09:57:01

0

,一旦你有相同的名称“富”属性将覆盖名称“富”的访问行为 唯一的出路似乎明确设置“富”在字典

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

是的,它不觉得“干”。然而,当你像试图做的那样“包装”一些新功能的类时,它可以避免很多问题。

+0

是的,我的确在寻找更多的“pythonic”方法来组织我的代码,而且我一直在质疑基于继承的方法。尽管如此,您的替代方案对我来说并不那么令人信服,因为我有几个级别的深度继承链,每个级别都定义了新功能。不得不重新定义每个级别的所有方法肯定是不可行的。但我明白你的观点。 – UncleZeiv 2009-06-29 17:21:51

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 
0

老实说,这里要看的是你试图围绕一个简单的设计来扭曲你的代码。属性描述符处理'foo'属性的请求,并且你想完全绕过它们,这是错误的。你已经在造成Base。 init分配foobar._foo = 5,所以这正是getter需要看的地方。

Base类(对象): DEF 初始化(个体经营): 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 
相关问题