python - 覆盖时访问基类属性

标签 python class properties attributes overriding

考虑以下基本 Python 类:

class Foo(object):

    def __init__(self, a1):
        self._att1 = a1

    @property
    def att1(self):
        return self._att1

    @att1.setter
    def att1(self, a):
        try:
            self._att1 = a
        except TypeError:
            # handle exception
            print("Not allowed")

class Bar(Foo):
    def __init__(self):
        Foo.__init__(self, 100)

    @Foo.att1.setter
    def att1(self, a):
        # self.att1 = a * 0.5  # RecursionError: maximum recursion depth exceeded
        # Foo.att1 = a * 0.5  # attribute is not changed (base instances are though (?))
        # Foo.att1(self,a)  # TypeError: 'property' object is not callable
        super().att1.__set__(a * 0.5)   # AttributeError: 'int' object has no attribute '__set__'
        # ... some other additional code ...

a = Foo(5)
b = Bar()
b.att1 = 700

print(a.att1)
print(b.att1)

从子类的覆盖中调用基属性 setter 的语法是什么?我知道我可以直接设置 self._att1,但我想避免这种情况,因为这样我就需要重复异常处理代码。这只是一个简单的示例,我有更复杂的情况,其中基类在属性上实现了一些额外的操作,我想避免在派生类属性 setter 上重复相同的代码。

最佳答案

代码:

class Foo:
    def __init__(self, a1):
        self._att1 = a1

    @property
    def att1(self):
        return self._att1

    @att1.setter
    def att1(self, a):
        if not isinstance(a, int):
            print("Not allowed")
        else:
            self._att1 = a


class Bar(Foo):
    def __init__(self):
        Foo.__init__(self, 100)

    @Foo.att1.setter
    def att1(self, a):
        Foo.att1.fset(self, a * 2)


c = Bar()
print(c.att1)
c.att1 = 10
print(c.att1)
c.att1 = "some string"

输出:

100
20
Not allowed

UPD。

根据@chepner 的建议,我决定添加一些解释。

当您使用装饰器 @Foo.att1.setter 时,它不会像您预期的那样工作。

docs您可以看到 2 个声明属性的示例:使用 property() 函数分配类变量并使用 @property 装饰器。这两种方法是等价的,但我发现首先在演示提供的代码如何工作时更明显。

让我们使用 property() 函数而不是装饰器来重写类声明:

class Foo:
    def __init__(self, a1):
        self._att1 = a1

    def getatt1(self):
        return self._att1

    def setatt1(self, a):
        if not isinstance(a, int):
            print("Not allowed")
        else:
            self._att1 = a

    att1 = property(getatt1, setatt1)

class Bar(Foo):
    def __init__(self):
        super().__init__(100)

    def setatt1(self, a):
        Foo.att1.fset(self, a * 2)

    att1 = property(Foo.getatt1, setatt1)

如您所见,您没有覆盖属性,您正在创建具有相同名称的新属性,该属性隐藏基类属性。您可以使用以下代码证明这一点:

print(f"Foo.att1 is Bar.att1: {Foo.att1 is Bar.att1}")

在这两个声明中它都会返回False,这意味着这个类的属性对象不相同。

关于python - 覆盖时访问基类属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56327027/

相关文章:

Python 2.7 类方法赋值奇怪 - lambda 得到我想要的行为

python - Django split Models in différents models.py 文件给我导入循环

java - 获取银行程序java的唯一id

c++ - 创建随机数量的对象

ios - 如何制作 Segue 传递数据并仅在满足特定条件时执行

javascript - 如果包含键值对,则返回数组中的对象

制表符后的 Python 正则表达式匹配整数

python - 查找文本中的所有实例,最后一个单词也应该是使用 python 正则表达式进行搜索的开头

linux - 在 jar 中查找特定路径

ios - 声明属性的正确方法