【问题标题】:How to call a data member of the base class if it is being overwritten as a property in the derived class?如果基类的数据成员作为派生类中的属性被覆盖,如何调用它?
【发布时间】:2009-06-29 10:03:17
【问题描述】:

这个问题和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 的赋值不起作用。

总而言之,描述符协议似乎不能很好地与继承交互......

【问题讨论】:

    标签: python inheritance overloading descriptor


    【解决方案1】:

    如果你使用委托而不是继承,生活会更简单。这是 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 )
    

    是的,它不会感觉“干燥”。但是,当您尝试在新功能中“包装”某些类时,它可以避免很多问题。

    【讨论】:

    • 是的,我确实在寻找更多“pythonic”的方式来组织我的代码,并且我一直在质疑我的基于继承的方法。但是,在我的情况下,您的替代方案并不那么令人信服,因为我有几个级别的深度继承链,其中每个级别都定义了新功能。必须重新定义每个级别的所有方法肯定是不可行的。但我明白你的意思。
    • @UncleZeiv:这不是非此即彼的情况。你有很多很多的设计模式,包括策略、组合、委托和继承。专注于继承是一件坏事。
    【解决方案2】:

    定义

    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
    

    在你的吸气剂中,你几乎得到了你想要的。如果您需要self.fooBase的构造函数中设置的值,只需查看_foo,它是由@foo.setter正确设置的。

    【讨论】:

    • 所有的答案都非常有趣,我赞成其中的大部分,但这个是直截了当的,它真的让我理解了手头的问题。
    【解决方案3】:
    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
    

    【讨论】:

      【解决方案4】:

      一旦您拥有同名“foo”的属性,它就会覆盖名称“foo”的访问行为 唯一的出路似乎是您在 dict

      中明确设置了 'foo'

      顺便说一句:我使用 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
      

      【讨论】:

        【解决方案5】:

        老实说,这里要注意的是,您正试图围绕一个糟糕的设计扭曲您的代码。属性描述符处理对“foo”属性的请求,而您想完全绕过这些,这是错误的。您已经让 Base.init 分配 foobar._foo = 5,所以这也正是 getter 需要查看的位置。

        类基(对象): 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
        

        【讨论】:

          猜你喜欢
          • 2010-11-04
          • 2017-07-05
          • 2011-04-21
          • 1970-01-01
          • 2014-05-10
          • 2013-05-16
          • 1970-01-01
          • 2015-12-11
          • 1970-01-01
          相关资源
          最近更新 更多