由于这里的 cmets 和其他两个标记为 dups 的问题中的人似乎都以同样的方式对此感到困惑,我认为值得在 Alex Coventry's 之上添加一个额外的答案。
Alex 正在分配一个可变类型的值,例如一个列表,这与事物是否共享无关。我们可以通过id 函数或is 运算符看到这一点:
>>> class A: foo = object()
>>> a, b = A(), A()
>>> a.foo is b.foo
True
>>> class A:
... def __init__(self): self.foo = object()
>>> a, b = A(), A()
>>> a.foo is b.foo
False
(如果你想知道为什么我使用object() 而不是5,那是为了避免遇到我不想在这里讨论的另外两个问题;对于两个不同的原因,完全单独创建的5s 最终可能是数字5 的同一个实例。但完全单独创建的object()s 不能。)
那么,为什么 Alex 的示例中的 a.foo.append(5) 会影响 b.foo,而我的示例中的 a.foo = 5 不会?好吧,试试 Alex 的示例中的a.foo = 5,并注意它不会影响那里的b.fooeither。
a.foo = 5 只是将a.foo 变成5 的名称。这不会影响b.foo 或a.foo 曾经引用的旧值的任何其他名称。* 我们正在创建一个隐藏类属性的实例属性有点棘手,** 但是一旦你明白了,这里没有什么复杂的事情发生。
希望现在 Alex 使用列表的原因很明显:您可以改变列表这一事实意味着更容易显示两个变量命名同一个列表,也意味着在实际代码中了解您是否拥有两个列表或同一个列表的两个名称。
* 来自像 C++ 这样的语言的人的困惑是,在 Python 中,值不存储在变量中。值本身就存在于值域中,变量只是值的名称,而赋值只是为值创建一个新名称。如果有帮助,请将每个 Python 变量视为 shared_ptr<T> 而不是 T。
** 有些人通过使用类属性作为实例可能设置或不设置的实例属性的“默认值”来利用这一点。这在某些情况下可能很有用,但也可能令人困惑,所以要小心。