考虑以下基本 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/