Python:__dict__ 显示类对象的类属性,即使 __init__ 内部的行为改变了类属性

Sus*_*aul 2 python python-3.x

根据我的理解,

对于像列表这样的可变对象,如果底层对象支持像列表这样的变异,则 +=(增强赋值)会导致对象发生变异。当然,这不适用于不支持突变的不可变对象,因为__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 属性,这让我感到非常困惑。

有人可以帮我解决这个问题吗?

jua*_*aga 6

这可能有点微妙。你可以想到

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] 中被警告:

对于属性引用的目标,关于类和实例属性的警告同样 适用于常规赋值。

需要注意的是: