2011-07-29 45 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

相关问题