2011-07-29 44 views
3

考慮一個基類:超載Python類屬性的一種優雅的方式

class A(object): 
    def __init__(self, x): 
     self._x = x 

    def get_x(self): 
     #... 
     return self._x 

    def set_x(self, x): 
     #... 
     self._x = x 

    x = property(get_x, set_x) 

和派生類:

class B(A): 
    def set_x(self, x): 
     #... 
     self._x = x**2 

    x = property(A.get_x, set_x) 

是否有B類重載set_x()優雅的方式,無需再宣佈它和財產x?謝謝。

回答

2

嘗試這一個:

class A(object): 
    def __init__(self): 
     self._x = 0 

    def get_x(self): 
     #... 
     return self._x 

    def set_x(self, x): 
     #... 
     self._x = x 

    x = property(get_x, lambda self,x : self.set_x(x)) 

class B(A): 
    def set_x(self, x): 
     #... 
     self._x = x**2 

由lambda給出的額外間接方法將使虛擬set_x函數成爲可能。

+0

謝謝,rodrigo!正是我一直在尋找的東西:) –

3

添加額外的間接層(即使用一個鉤子):

class A(object): 
    def __init__(self, x): 
     self._x = x 

    # Using a _get_hook is not strictly necessary for your problem... 
    def _get_hook(self): 
     return self._x 
    def get_x(self): 
     return self._get_hook() 

    # By delegating `set_x` behavior to `_set_hook`, you make it possible 
    # to override `_set_hook` behavior in subclass B. 
    def _set_hook(self, x): 
     self._x=x 
    def set_x(self, x): 
     self._set_hook(x) 

    x = property(get_x, set_x) 

class B(A): 
    def _set_hook(self, x): 
     print('got here!') 
     self._x = x**2 

b=B(5) 
b.x=10 
# got here! 
print(b.x) 
# 100 

對於Python的現代版本,你也可以使用@property裝飾:

class A(object): 

    @property 
    def x(self): 
     return self._get_hook() 

    @x.setter 
    def x(self, x): 
     self._set_hook(x) 
+0

謝謝,我認爲這種方法,但你不覺得添加鉤子比重新聲明setter更令人困惑嗎? –

+0

@BasicWolf:實際上,我認爲使用鉤子比重新聲明整個屬性更清晰。請注意,當您「重新聲明」屬性時,實際上是在'class B'中定義一個新的屬性對象。所以用你的方法,你最終會在'class A'和'class B'中得到一個屬性對象。對於您定義的每個附加子類,您可能會得到另一個屬性。相反,使用鉤子可以使控制流程變得清晰和簡單。 – unutbu

+0

@BasicWolf:就速度而言,或許你的方式更好,因爲它涉及更直接的屬性查找和更少的函數調用,但就組織而言,我認爲使用鉤子更好。而且,在設計之前擔心速度是錯誤的預優化。 – unutbu

相關問題