如果两个变量指向同一个对象,为什么重新分配一个变量不会影响另一个变量?

2025-03-26 09:10:00
admin
原创
14
摘要:问题描述:我试图理解变量在 Python 中的工作方式。假设我在变量中存储了一个对象a:>>> a = [1, 2, 3] 如果我分配a给b,两者都指向同一个对象:>>> b = a >>> b is a True 但如果我重新分配a或b,情况就不再如此:...

问题描述:

我试图理解变量在 Python 中的工作方式。假设我在变量中存储了一个对象a

>>> a = [1, 2, 3]

如果我分配ab,两者都指向同一个对象:

>>> b = a
>>> b is a
True

但如果我重新分配ab,情况就不再如此:

>>> a = {'x': 'y'}
>>> a is b
False

这两个变量现在具有不同的值:

>>> a
{'x': 'y'}
>>> b
[1, 2, 3]

我不明白为什么变量现在不同了。为什么a is b不再正确?有人能解释一下发生了什么吗?


解决方案 1:

Python 中的名称指的是对象。对象独立于名称而存在,名称也独立于其所引用的对象而存在。

# name a
a = 1337
    # object 1337

当将“名称赋给名称”时,右侧将计算为所引用的对象。与2 + 2计算为类似4a计算为原始1337

# name b
b = a
    # object referred to by a -> 1337

此时,我们有a -> 1337b -> 1337- 请注意,两个名字都不认识对方!如果我们测试a is b,两个名称将被评估为同一个对象,这显然是相等的。

重新分配名称只会改变该名称所指的内容 - 不存在可以更改其他名称的联系。

# name a - reassign
a = 9001
  # object 9001

此时,我们有a -> 9001b -> 1337。如果我们现在测试a is b,两个名称将被评估为不同的对象,它们是不一样的。


如果您使用过 C 等语言,那么您会习惯于包含值的变量。例如,char a = 12可以读作“a是包含 的内存区域12”。最重要的是,您可以让多个变量使用相同的内存。将另一个值赋给变量会更改共享内存的内容 - 从而更改两个变量的值。

+- char a -+
|       12 |
+--char b -+

# a = -128

+- char a -+
|     -128 |
+--char b -+

这不是 Python 的工作方式:名称不包含任何内容,但引用单独的值。例如,a = 12可以读作“a是一个引用值的名称12”。最重要的是,您可以让多个名称引用同一个值 - 但它们仍然是单独的名称,每个名称都有自己的引用。将另一个值分配给名称会更改该名称的引用 - 但另一个名称的引用保持不变。

+- name a -+ -\n               \n                --> +- <12> ---+
               /    |       12 |
+- name b -+ -/     +----------+

# a = -128
                    +- <-128> -+
+- name a -+ -----> |     -128 |
                    +----------+

                    +- <12> ---+
+- name b -+ -----> |       12 |
                    +----------+

容易让人混淆的是,可变对象似乎违反了名称和对象的分离。通常,这些是容器(例如list,,dict...),并且类默认表现出相同的行为。

# name m
m = [1337]
    # object [1337]
# name n
n = m
    # object referred to by m

与普通整数 类似1337,包含整数的列表[1337]是可以用多个独立名称引用的对象n is m。如上所述,计算结果为True并且m = [9001]不会改变n

但是,对名称执行某些操作会改变该名称和所有别名所看到的值。

# inplace add to m
m += [9001]

经过此操作后,m == [1337, 9001] n is m仍然成立。事实上,看到的值n也变为了[1337, 9001]。这似乎违反了上述行为,其中别名不会相互影响。

这是因为m += [9001]并没有改变m所引用的内容。它只改变了所引用的列表(和别名)的内容。和仍然引用原始列表对象,其已更改。m`nmn`

+- name m -+ -\n                                 
                --> +- […] -+     +--- <@0> -+
               /    |    @0 |  -> |     1337 |
+- name n -+ -/     +-------+     +----------+

# m += [9001]

+- name m -+ -\n                                 
                --> +- […] -+     +--- <@0> -++--- <@1> -+
               /    | @0 @1 |  -> |     1337 ||     9001 |
+- name n -+ -/     +-------+     +----------++----------+

解决方案 2:

在 Python 中,所有变量都存储在字典或看起来很像字典的结构中(例如,locals()可以将当前范围/命名空间显示为字典)。

注意PyObject*是 CPython 概念。我不确定在其他 Python 实现中情况如何。

因此,将 Python 变量视为具有精确内存位置的 C 变量是错误的。它们的PyObject*(指针或内存位置),而不是实际的原始值。由于变量本身只是指向PyObject*指针的字典中的条目,因此更改变量的值实际上是为其提供了一个不同的内存地址。

在 CPython 中,这些值被和PyObject*使用(与 相同)。id`isa is bid(a) == id(b)`

例如,让我们考虑一下简单的代码行:

# x: int
x += 1

实际上改变了与变量关联的内存位置。这是因为它遵循以下逻辑:

LOAD_FAST (x)
LOAD_CONST (1)
INPLACE_ADD
STORE_FAST (x)

字节码大致如下:

  1. 查找 x 的值。在 CPython 中,它是PyObject*指向PyLongLong或 这样的(int来自 Python 用户空间)

  2. 从常量内存地址加载值

  3. 将两个值相加。这将产生一个新的PyObject*,它也是一个int

  4. 将与之关联的值设置x为这个新指针

TL;DR:Python 中的所有内容(包括基元)都是对象。变量本身并不存储值,而是存储封装它们的指针。重新分配变量会更改与该名称关联的指针,而不会更新保存在该位置的内存。

解决方案 3:

假设我在变量 a 中存储了一个对象”——这就是你错的地方。

Python 对象不存储在变量,而是通过变量引用

a = [1, 2, 3]
b = a

ab引用同一个对象。该list对象的引用计数为 2,因为有两个名称引用它。

a = {'x': 'y'}

a不再引用同一个list对象,而是引用一个dict对象。这会减少该对象的引用计数list,但b仍引用该对象,因此该对象的引用计数现在为 1。

b = None

这意味着b现在引用了None对象(该对象的引用计数非常高,许多名称都引用了None)。该list对象的引用计数再次减少,并降至零。此时,该list对象可以被垃圾回收,内存被释放(何时发生这种情况无法保证)。

参见sys.getrefcount

解决方案 4:

我用外行人能理解的语言向你解释,以便你能够轻松理解。

案例1

a = [1, 2, 3]
b = a
print(b is a)

的值a[1,2,3]。现在我们将也[1,2,3]赋给。因此两者具有相同的值,因此 = 。b`ab is aTrue`

下一步,

a = {'x': 'y'}
print(a is b) 

现在您将 的值更改a为 ,{'x':'y'} 我们的b值仍然与 相同[1,2,3]。因此现在a is bFalse

案例 2如果您已完成以下操作:-

a = [1, 2, 3]
b = a
print(b is a)
a = {'x': 'y'}
b = a  # Reassigning the value of b.
print(a is b)

重新分配 的值后a,我还将重新分配 的值。因此,在两种情况下b您都会得到。True

我希望这对你有帮助。

相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   2079  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1459  
  建筑行业正处于数字化转型的关键时期,建筑产品生命周期管理(PLM)系统的实施对于提升项目效率、质量和协同性至关重要。特别是在 2025 年,基于建筑信息模型(BIM)的项目进度优化工具成为众多建筑企业关注的焦点。这些工具不仅能够整合项目全生命周期的数据,还能通过精准的分析和模拟,为项目进度管理提供强大支持。BIM 与建...
plm是什么软件   0  
  PLM系统开发的重要性与现状PLM(产品生命周期管理)系统在现代企业的产品研发、生产与管理过程中扮演着至关重要的角色。它贯穿产品从概念设计到退役的整个生命周期,整合了产品数据、流程以及人员等多方面的资源,极大地提高了企业的协同效率和创新能力。通过PLM系统,企业能够实现产品信息的集中管理与共享,不同部门之间可以实时获取...
国产plm软件   0  
  PLM(产品生命周期管理)系统在企业产品研发与管理过程中扮演着至关重要的角色。随着市场竞争的加剧和技术的飞速发展,企业对PLM系统的迭代周期优化需求日益迫切。2025年敏捷认证对项目管理提出了新的要求,其中燃尽图作为一种强大的可视化工具,在PLM系统迭代周期优化中有着广泛且重要的应用。深入探讨这些应用,对于提升企业的项...
plm系统主要干什么的   0  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用