根据我的理解,
对于像列表这样的可变对象,如果底层对象支持像列表这样的变异,则 +=(增强赋值)会导致对象发生变异。当然,这不适用于不支持突变的不可变对象,因为__iadd__它不存在并且__add__是被调用的对象。
考虑以下代码:
class TestClass:
bar = []
def __init__(self, x):
self.bar += [x]
f = TestClass(1)
g = TestClass(2)
h = TestClass(3)
print(f.bar)
print(g.bar)
print(TestClass.bar)
Run Code Online (Sandbox Code Playgroud)
现在,我明白为什么所有三个 g,f,h 都会打印出来,[1, 2, 3]因为我们正在“改变”类属性。
但是当我尝试通过执行来查看对象的命名空间时 print(f.__dict__)查看,我也看到了对象内部的 bar 属性。
问题 1:如果发生变异的实际属性是类属性,为什么在对象命名空间中创建实例?
其次,“如果”在对象中创建了该实例变量(如 f),那么f.bar += 4应该只影响对象 f,因为 f 中的新实例变量 bar 应该遮蔽了类属性。但是我看到f.bar+=4反过来这样做也会更新 class 属性,这让我感到非常困惑。
有人可以帮我解决这个问题吗?
这可能有点微妙。你可以想到
self.bar += [x]
Run Code Online (Sandbox Code Playgroud)
相当于
self.bar = self.bar.__iadd__([x])
Run Code Online (Sandbox Code Playgroud)
因此,self.bar.__iadd__([x])改变列表,本质上是调用list.extend,然后返回列表对象。此列表对象与 所引用的对象相同TestClass.bar,被分配给实例属性。
所以现在你有一个与 class 属性同名的实例属性,并且两者碰巧绑定到同一个列表对象
这甚至在 [documentation] 中被警告:
对于属性引用的目标,关于类和实例属性的警告同样 适用于常规赋值。
需要注意的是:
| 归档时间: |
|
| 查看次数: |
40 次 |
| 最近记录: |