【问题标题】:An elegant way of overloading Python class properties一种重载 Python 类属性的优雅方式
【发布时间】:2011-10-15 18:49:09
【问题描述】:

考虑一个基类:

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?谢谢你。

【问题讨论】:

    标签: python properties overloading


    【解决方案1】:

    添加一个额外的间接层(即使用挂钩):

    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)
    

    【讨论】:

    • 谢谢,我考虑过这种方法,但你不觉得添加钩子比重新声明 setter 更令人困惑吗?
    • @BasicWolf:实际上,我认为使用钩子比重新声明整个属性更清晰。请注意,当您“重新声明”该属性时,您实际上是在 class B 中定义了一个新的属性对象。因此,通过您的方法,您最终会在class Aclass B 中获得一个属性对象。对于您定义的每个附加子类,您最终可能会得到另一个属性。相比之下,使用钩子可以让控制流变得清晰和简单。
    • @BasicWolf:在速度方面,也许你的方式更好,因为它涉及更直接的属性查找和更少的函数调用,但在组织方面,我认为使用钩子更好。此外,在设计之前担心速度是一种错误的预优化。
    【解决方案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 函数虚拟化。

    【讨论】:

    • 谢谢你,罗德里戈!正是我一直在寻找的:)
    猜你喜欢
    • 2014-10-04
    • 2021-08-14
    • 1970-01-01
    • 2015-08-28
    • 1970-01-01
    • 1970-01-01
    • 2011-09-18
    • 2011-08-10
    • 2011-08-30
    相关资源
    最近更新 更多