2009-06-29 35 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 
相關問題