【问题标题】:How to decorate a parent property's getter or setter?如何装饰父属性的 getter 或 setter?
【发布时间】:2021-11-04 19:43:12
【问题描述】:

我在父类Shape 中定义了一个属性area 及其getter。在子类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()

当我运行代码时,我没有得到“你好孩子”:

>>> sq.area
hello parent

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

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

而不是没有self。然后我需要在父级中定义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 告诉我 def area(self): 中的 Square 行“覆盖 Shape 中的方法”。 此外,IDE 在Shape.area.fget(self) 中还说,self 是一个意外参数。即使代码运行没有错误。

感觉第 2 版是一个 hack。为什么我的ide在抱怨?我以为在第2版我并没有定义一个全新的area,只是装饰了继承的areafget,不是吗?

【问题讨论】:

    标签: python properties decorator


    【解决方案1】:

    如果你想让子类的area属性的getter使用父类的area属性并扩展它的值,在这种情况下子类的getter函数应该调用super()来访问父类的财产。至于让孩子的 setter 使用父母的 setter,您必须通过父类属性的 fset 属性访问父母的 setter:

    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
    

    或者,您可以在子类中定义新的 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)
    

    【讨论】:

    • 感谢您的解释。这行得通;但我想保留父级中定义的area,例如,它的setter 可以在其父级中定义。那我该怎么做呢?
    • 我明白了。对于 setter super() 将无法在分配中工作,因此您必须直接调用父级的 setter 方法。我已经相应地更新了答案。
    • 再次感谢。所以我是否正确理解没有办法仅仅“装饰”父母的财产。唯一的方法是覆盖 area,并以某种方式将父级area 的fget 和fset '移植'到新的子级中。
    • 不太清楚装饰父母的财产是什么意思。我已经用我认为您可能的意思更新了我的答案。
    • 我的意思是,在你的回答中,Square 中有这两行:@property\\def area(self): 定义了一个全新的area 属性,对吗?我用代码的第 2 版更新了我的问题,也许这可以更好地解释我对代码的预期行为。
    【解决方案2】:

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

    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 会在运行代码时引发错误。我不明白这一点。感觉这是一个 hack。

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

    【讨论】:

      猜你喜欢
      • 2017-11-28
      • 1970-01-01
      • 1970-01-01
      • 2020-12-04
      • 2017-06-13
      • 1970-01-01
      • 1970-01-01
      • 2023-03-10
      • 1970-01-01
      相关资源
      最近更新 更多