python 引用如何工作?为什么列表共享对其他引用所做的修改,而整数不共享?



以下代码片段:

a = [1,2,3,4,5]
b = a
b.append(6)
print(a)
print(b)

指纹

[1, 2, 3, 4, 5, 6]
[1, 2, 3, 4, 5, 6]

所以在修改b的时候,我们也会修改通过a可访问的列表。

但是,对于整数,此代码段:

a = 1
b = a
b +=1
print(a)
print(b)

指纹

1
2

所以在这里,ab似乎没有引用同一件事?为什么第二个代码段中的a值不是 2?

在 Python 中,一切都是一个对象。一切都是每个文档的地址(指针)的名称

在该页面上,您可以向下滚动并找到以下内容:

数值对象是不可变的;一旦创建,它们的值永远不会改变

在此之下,您将看到定义的int类型,因此您的第二个示例非常有意义。

在同一页面的顶部,您将找到以下内容:

每个对象都有一个标识、类型和值。对象的身份在创建后永远不会更改;您可以将其视为对象在内存中的地址。

Python 的行为与 C 和 Java 类似,因为您无法重新分配指向名称的指针指向的位置。Python和Java一样,也是按值传递的,没有逐个引用的语义。

看看你的第一个例子:

>>> a = 1
>>> hex(id(a))
'0x7ffdc64cd420'
>>> b = a + 1
>>> hex(id(b))
'0x7ffdc64cd440'
>>> print(a)
1
>>> print(b)
2

这里显示,操作b = a + 1a1b现在2。这是因为int是不可变的,指向值的名称将始终指向同一地址1

>>> a = 1
>>> b = 2
>>> c = 1
>>> hex(id(a))
'0x7ffdc64cd420'
>>> hex(id(b))
'0x7ffdc64cd440'
>>> hex(id(c))
'0x7ffdc64cd420'

现在,这仅适用于 C 实现中要256-5值,因此除此之外,您将获得新地址,但上面显示的可变性仍然存在。我向您展示了内存地址的共享是有原因的。在同一页面上,您将找到以下内容:

类型几乎会影响对象行为的所有方面。甚至对象标识的重要性在某种意义上也会受到影响:对于不可变类型,计算新值的操作实际上可能会返回对具有相同类型和值的任何现有对象的引用,而对于可变对象,这是不允许的。例如,在 a = 1 之后;b = 1,a 和 b 可能引用也可能不引用值为 1 的同一对象,具体取决于实现,但在 c = [] 之后;d = [],c 和 d 保证引用两个不同的、唯一的、新创建的空列表。(请注意,c = d = [] 将同一对象同时分配给 c 和 d。

所以你的例子:

>>> a = [1, 2, 3, 4, 5]
>>> hex(id(a))
'0x17292e1cbc8'
>>> b = a
>>> hex(id(b))
'0x17292e1cbc8'

我应该可以在这里停下来,很明显,ab都引用地址0x17292e1cbc8处内存中的同一对象。那是因为上面就像在说:

# Lets assume that `[1, 2, 3, 4, 5]` is 0x17292e1cbc8 in memory
>>> a = 0x17292e1cbc8
>>> b = a
>>> print(b)
'0x17292e1cbc8'

又长又瘦?您只需将指针分配给一个新名称,但两个名称都指向内存中的同一对象!注意:这与浅拷贝不同,因为不会创建外部复合对象。

最新更新