93

我正在将我的一些类从广泛使用 getter 和 setter 更改为更 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
4

7 回答 7

111

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

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)
于 2009-06-20T11:51:38.787 回答
63

super()应该做的伎俩:

return super().bar

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

return super(FooBar, self).bar
于 2009-06-20T11:46:49.080 回答
28

有一种替代方法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的属性setter:

到目前为止,我看到的最好的建议如下:

A.prop.fset(self, value)

我相信这个更好:

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

在此示例中,两个选项是等效的,但使用 super 的优点是独立于B. 如果B要从也扩展属性的类继承,C则不必更新B's 代码。

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)

一个警告:

除非您的属性没有 setter,否则B即使您只更改其中一个的行为,您也必须同时定义 setter 和 getter。

于 2016-06-06T17:14:41.853 回答
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
于 2009-06-20T11:50:09.320 回答
3

对马克西姆的回答进行了一些小的改进:

  • 使用__class__避免书写B。请注意,这self.__class__是 的运行时类型self,但__class__ 没有 self是封闭类定义的名称。super()是 的简写super(__class__, self)
  • 使用__set__而不是fset. 后者特定于propertys,但前者适用于所有类似属性的对象(描述符)。
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)
于 2020-03-19T22:51:59.263 回答
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)
于 2020-10-05T13:01:49.093 回答
-4
    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()

(除非我从你的解释中遗漏了什么)

于 2009-06-20T11:51:44.030 回答