如何修饰parent属性的getter或setter?

How to decorate a parent property's getter or setter?

我在parentclassShape中定义了属性area及其getter。在 child class Square 中,我想扩展 area 的 getter 功能。我写了一些不起作用的东西:

版本 1

class Shape:
    def __init__(self):
        self._area = None

    @property
    def area(self):
        print('hello parent')
        return self._area
    
    # setter of `area` could be also defined here; hence in the child
    # I would like to keep `area`, only decorating its getter.

class Square(Shape):
    def __init__(self):
        super(Square, self).__init__()

        area = Shape.area.getter(self.dosomething())

    def dosomething(self):
        def new_func():
            print('hello child')
            Shape.area.fget(self)
        return new_func

sq = Square()

当我 运行 代码时,我没有得到 'hello child':

>>> sq.area
hello parent

我上面的代码有一些明显的问题。例如,在 Square 我应该有

self.area = Shape.area.getter(self.dosomething())

而不是没有self。然后我需要在 parent...

中定义 areasetter

版本 2

经过一番摆弄,我想出了下面的代码,

class Shape:
    def __init__(self):
        self._area = None

    @property
    def area(self):
        print('hello parent')
        return self._area


class Square(Shape):
    def __init__(self):
        super(Square, self).__init__()

    @Shape.area.getter
    def area(self):
        print('hello child')
        Shape.area.fget(self)


sq = Square()

这次好像如我所愿:

>>> sq.area
hello child
hello parent

但是,我的 ide 告诉我 Square 中的行 def area(self): “overrides method in Shape”。 此外,IDE在Shape.area.fget(self)中也说,self是一个意想不到的论点。即使代码 运行s 没有错误。

感觉版本 2 是一个 hack。为什么我的 ide 在抱怨?我以为在版本2中我没有定义一个brand-newarea,只是装饰继承areafget,不是吗?

如果你想使 child class' area 属性 的 getter 使用 parent's area 属性 并扩展它的值,在这种情况下 child 的 getter 函数应该调用 super() 来访问 parent 的属性。至于让 child 的 setter 使用 parent 的 setter,你必须访问 parent 的 setter通过 parent class' 属性:

fset 属性
class Shape:
    def __init__(self):
        self._area = 'hello parent'

    @property
    def area(self):
        return self._area

    @area.setter
    def area(self, value):
        self._area = value

class Square(Shape):
    @property
    def area(self):
        return super().area + ' and child'

    @area.setter
    def area(self, value):
        Shape.area.fset(self, 'very ' + value)

sq = Square()
print(sq.area)
sq.area = 'new parent'
print(sq.area)

这输出:

hello parent and child
very new parent and child

或者,您可以在 child class 中定义新的 getter 和 setter 方法并在它们上调用 property

class Square(Shape):
    def area_getter(self):
        return super().area + ' and child'

    def area_setter(self, value):
        Shape.area.fset(self, 'very ' + value)

    area = property(area_getter, area_setter)

摆弄后我得出了这个解决方案:

class Shape:
    def __init__(self):
        self._area = None

    @property
    def area(self):
        print('hello parent')
        return self._area

    @area.setter
    def area(self, val):
        print('parent setter')
        self._area = val


class Square(Shape):
    def __init__(self):
        super(Square, self).__init__()

    @Shape.area.getter
    def area(self):
        print('hello child')
        return super().area

    @area.setter
    def area(self, val):
        print('setter in child')
        Shape.area.fset(self, val)  # IDE complains that val is unexpected. Why?


sq = Square()

它做了我想要的,还有一个问题:ide 抱怨 valSquare 的 setter 部分出乎意料(在代码中注明) .虽然这运行没有问题。在 运行 代码中删除该行中的 self 会引发错误。我不明白这一点。感觉这是一个黑客。

我认为我得出的结论是您不应该扩展父 class 的属性。