如果在派生类中覆盖此属性,如何调用基类的属性?

时间:2009-06-20 11:37:15

标签: python inheritance properties overloading descriptor

我正在改变我的一些类别,从大量使用吸气剂和制定者到使用更多的pythonic属性。

但是现在我被卡住了,因为我之前的一些getter或setter会调用基类的相应方法,然后执行其他操作。但是如何通过属性实现这一目标呢?如何在父类中调用属性getter或setter?

当然只是调用属性本身就会产生无限递归。

class Foo(object):

    @property
    def bar(self):
        return 5

    @bar.setter
    def bar(self, a):
        print a

class FooBar(Foo):

    @property
    def bar(self):
        # return the same value
        # as in the base class
        return self.bar # --> recursion!

    @bar.setter
    def bar(self, c):
        # perform the same action
        # as in the base class
        self.bar = c    # --> recursion!
        # then do something else
        print 'something else'

fb = FooBar()
fb.bar = 7

7 个答案:

答案 0 :(得分:87)

您可能认为可以调用属性调用的基类函数:

class FooBar(Foo):

    @property
    def bar(self):
        # return the same value
        # as in the base class
        return Foo.bar(self)

虽然这是最明显的尝试,我认为 - 它不起作用,因为bar是属性,而不是可调用。

但是属性只是一个对象,使用getter方法来查找相应的属性:

class FooBar(Foo):

    @property
    def bar(self):
        # return the same value
        # as in the base class
        return Foo.bar.fget(self)

答案 1 :(得分:44)

Super应该这样做:

return super().bar

在Python 2.x中,您需要使用更详细的语法:

return super(FooBar, self).bar

答案 2 :(得分:18)

使用super的替代方法不需要显式引用基类名称。

基类A:

class A(object):
    def __init__(self):
        self._prop = None

    @property
    def prop(self):
        return self._prop

    @prop.setter
    def prop(self, value):
        self._prop = value

class B(A):
    # we want to extend prop here
    pass

在B中,访问父类A的属性getter:

正如其他人已经回答的那样,它是:

super(B, self).prop

或者在Python 3中:

super().prop

这将返回属性的getter返回的值,而不是getter本身,但它足以扩展getter。

在B中,访问父类A的属性设置器:

我目前看到的最佳建议如下:

A.prop.fset(self, value)

我相信这个更好:

super(B, self.__class__).prop.fset(self, value)

在此示例中,两个选项都是等效的,但使用super具有独立于B的基类的优点。如果B继承了C类,同时扩展了该属性,则无需更新B代码。

B扩展A属性的完整代码:

class B(A):
    @property
    def prop(self):
        value = super(B, self).prop
        # do something with / modify value here
        return value

    @prop.setter
    def prop(self, value):
        # do something with / modify value here
        super(B, self.__class__).prop.fset(self, value)

一个警告:

除非你的财产没有设置者,否则你必须在B中定义setter和getter,即使你只改变其中一个的行为。

答案 3 :(得分:4)

@property
def bar:
    return super(FooBar, self).bar

虽然我不确定python是否支持调用基类属性。属性实际上是一个可调用对象,它使用指定的函数进行设置,然后在类中替换该名称。这很容易意味着没有超级功能可用。

您可以随时切换语法以使用property()函数:

class Foo(object):

    def _getbar(self):
        return 5

    def _setbar(self, a):
        print a

    bar = property(_getbar, _setbar)

class FooBar(Foo):

    def _getbar(self):
        # return the same value
        # as in the base class
        return super(FooBar, self)._getbar()

    def bar(self, c):
        super(FooBar, self)._setbar(c)
        print "Something else"

    bar = property(_getbar, _setbar)

fb = FooBar()
fb.bar = 7

答案 4 :(得分:1)

Maxime's answer的一些小改进:

  • 使用__class__避免编写B。请注意,self.__class__self的运行时类型,但是__class__ without self是封闭类定义的名称。 super()super(__class__, self)的简写。
  • 使用__set__代替fset。后者特定于property,但前者适用于所有类似属性的对象(描述符)。
class B(A):
    @property
    def prop(self):
        value = super().prop
        # do something with / modify value here
        return value

    @prop.setter
    def prop(self, value):
        # do something with / modify value here
        super(__class__, self.__class__).prop.__set__(self, value)

答案 5 :(得分:0)

您可以使用以下模板:

class Parent():
    def __init__(self, value):
        self.__prop1 = value

    #getter
    @property
    def prop1(self):
        return self.__prop1

    #setter
    @prop1.setter
    def prop1(self, value):
        self.__prop1 = value

    #deleter
    @prop1.deleter
    def prop1(self):
        del self.__prop1
  
class Child(Parent):

    #getter
    @property
    def prop1(self):
        return super(Child, Child).prop1.__get__(self)

    #setter
    @prop1.setter
    def prop1(self, value):
        super(Child, Child).prop1.__set__(self, value)

    #deleter
    @prop1.deleter
    def prop1(self):
        super(Child, Child).prop1.__delete__(self)

注意!必须一起重新定义所有属性方法。如果不想重新定义所有方法,请改用以下模板:

class Parent():
    def __init__(self, value):
        self.__prop1 = value

    #getter
    @property
    def prop1(self):
        return self.__prop1

    #setter
    @prop1.setter
    def prop1(self, value):
        self.__prop1 = value

    #deleter
    @prop1.deleter
    def prop1(self):
        del self.__prop1


class Child(Parent):

    #getter
    @Parent.prop1.getter
    def prop1(self):
        return super(Child, Child).prop1.__get__(self)

    #setter
    @Parent.prop1.setter
    def prop1(self, value):
        super(Child, Child).prop1.__set__(self, value)

    #deleter
    @Parent.prop1.deleter
    def prop1(self):
        super(Child, Child).prop1.__delete__(self)

答案 6 :(得分:-2)

    class Base(object):
      def method(self):
        print "Base method was called"

    class Derived(Base):
      def method(self):
        super(Derived,self).method()
        print "Derived method was called"

    d = Derived()
    d.method()

(除非我遗漏了你的解释)