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

Unc*_*eiv 81 python inheritance overloading properties descriptor

我正在改变我的一些类别,从广泛使用吸气剂和制定者到更加诡计多端的财产使用.

但现在我被卡住了,因为我之前的一些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
Run Code Online (Sandbox Code Playgroud)

Dav*_*eau 92

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

class FooBar(Foo):

    @property
    def bar(self):
        # return the same value
        # as in the base class
        return Foo.bar(self)
Run Code Online (Sandbox Code Playgroud)

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

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

class FooBar(Foo):

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

  • 设置者的+1 ...和Foo.bar.fset(self,c) (9认同)
  • 不要自己解决MRO,使用`super`. (6认同)
  • 我得到一个TypeError:'property'对象不可调用 (2认同)

Pan*_*rat 47

超级应该做的伎俩:

return super().bar
Run Code Online (Sandbox Code Playgroud)

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

return super(FooBar, self).bar
Run Code Online (Sandbox Code Playgroud)

  • 对于getter来说,super().bar似乎工作正常,但是对于通过重写的setter中的base属性进行赋值不起作用.如果我做super().bar = 3我得到AttributeError:'super'对象没有属性'bar' (5认同)
  • 我猜(好吧,通过链接来判断:P),这个答案与python3有关.在python3中,super()可以采用零参数,是的. (4认同)
  • super(MyClass,self).bar() (3认同)
  • 类型错误:super() 至少需要 1 个参数(给定 0 个) (2认同)
  • 虽然这适用于获取,但它无法使用 `AttributeError` 进行设置。 (2认同)

Max*_* R. 19

有一个替代使用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
Run Code Online (Sandbox Code Playgroud)

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

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

super(B, self).prop
Run Code Online (Sandbox Code Playgroud)

或者在Python 3中:

super().prop
Run Code Online (Sandbox Code Playgroud)

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

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

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

A.prop.fset(self, value)
Run Code Online (Sandbox Code Playgroud)

我相信这个更好:

super(B, self.__class__).prop.fset(self, value)
Run Code Online (Sandbox Code Playgroud)

在这个例子中,两个选项都是等价的,但是使用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)
Run Code Online (Sandbox Code Playgroud)

一个警告:

除非你的属性没有setter,否则你必须定义setter和getter,B即使你只改变其中一个的行为.


Eri*_*ric 5

对马克西姆的答案的一些小改进:

  • 用于__class__避免写入B。请注意,self.__class__是 的运行时类型self,但__class__ without 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)
Run Code Online (Sandbox Code Playgroud)