Python有指向对象的名称。对象与名称是分开存在的,名称也与其所指向的对象是分离的。
a = 1337
当为“名称分配名称”时,右侧将
评估所引用的对象。类似于
2 + 2
求值为
4
,
a
求值为原始
1337
。
b = a
现在,我们有 a -> 1337
和 b -> 1337
- 注意,这两个名称彼此不知道!如果我们测试 a is b
,那么这两个名称都会被评估为相同的对象,显然是相等的。
重新分配一个名称只会改变该名称所指的内容 - 没有其他名称可以通过连接来进行更改。
a = 9001
现在,我们有a -> 9001
和b -> 1337
。如果我们现在测试a is b
,则两个名称都被评估为不同的对象,它们不相同。
如果您来自像C这样的语言,则习惯于变量包含值。例如,char a = 12
可以解读为"a
是一个包含12
的内存区域"。此外,您可以让多个变量使用相同的内存。将另一个值分配给变量会更改共享内存的内容-因此也更改了两个变量的值。
+- char a -+
| 12 |
+--char b -+
+- char a -+
| -128 |
+--char b -+
这并不是 Python 的工作方式:变量名并不包含任何内容,而是指向各自的值。例如,a = 12
可以理解为“a
是一个指向值为 12
的变量名”。此外,你可以拥有多个变量名指向同一个值 - 但它们仍然是不同的变量名,每个都有自己的引用。将另一个值分配给变量名会更改该变量名的引用 - 但不会影响其他变量名的引用。
+- name a -+ -\
\
--> +- <12> ---+
/ | 12 |
+- name b -+ -/ +----------+
+- <-128> -+
+- name a -+ -----> | -128 |
+----------+
+- <12> ---+
+- name b -+ -----> | 12 |
+----------+
一个令人困惑的点是,
可变对象似乎违反了名称和对象的分离。通常,这些是容器(例如
list
,
dict
等),类默认表现出相同的行为。
一个容易混淆的地方是,
可变的对象看起来违反了名称和对象的分离原则。通常来说,这些对象是容器(如
list
,
dict
等),而且类默认也表现出相同的行为。
m = [1337]
n = m
与普通整数
1337
类似,包含整数
[1337]
的列表是一个可以被多个独立名称引用的
对象。就像上面一样,
n is m
的结果为
True
,而
m = [9001]
不会改变
n
的值。
然而,对某些名称的特定操作将更改和所有别名看到的值。
m += [9001]
执行此操作后,m == [1337, 9001]
并且 n is m
仍然成立。实际上,n
看到的值也已经更改为 [1337, 9001]
。这似乎违反了上面的行为,其中别名不会相互影响。
这是因为 m += [9001]
没有更改 m
所引用的内容,它只更改了 m
(和别名 n
)所引用的列表的 内容。 m
和 n
仍然引用原始的列表对象,其值已更改。
+- name m -+ -\
\
/ | @0 | -> | 1337 |
+- name n -+ -/ +
# m += [9001]
+- name m -+ -\
\
/ | @0 @1 | -> | 1337 || 9001 |
+- name n -+ -/ +