了解 Python 中的内存寻址



我写这篇文章是为了扩展我对pointersmemory-addressing如何在python中工作的理解。

Python是一种高级语言,我了解到内存管理由python负责。

我还了解到指针可以用id()对象来识别。

假设我有两个变量ab,这两个变量可以用以下命令交换:

a,b=b,a

可以使用以下方法找到这些变量identity的变化。

>>> a=2
>>> b=3
>>> id(a)
140732857872688
>>> id(b)
140732857872720
>>> a,b=b,a
>>> a
3
>>> b
2
>>> id(a)
140732857872720
>>> id(b)
140732857872688

如您所见,ids被交换(如预期的那样(,换句话说,我们可以说分配给变量的ids被交换了。这在python中是如何发生的?

再举一个例子,

>>> i=0
>>> id(i)
140732857872624
>>> i+=1
>>> id(i)
140732857872656

i递增1时,如何在引擎盖下创建具有相同名称的新变量(我称它为new,因为身份正在更改(?

我再添加一个例子来进一步扩展我的问题!

操作 1:

>>> i,j=0,0
>>> id(i)
140732857872624
>>> id(j)
140732857872624
>>> i,j = i+1,i+1
>>> i
1
>>> j
1
>>> id(i)
140732857872656
>>> id(j)
140732857872656

操作 2:

>>> i,j=0,0
>>> i=i+1
>>> j=i+1
>>> i
1
>>> j
2
>>> id(i)
140732857872656
>>> id(j)
140732857872688

当然,操作 1 和操作 2 是不同的。这两个操作如何在低级别发生。

一旦已经分配的指针不再有用,它将如何重用? 如果一个memory-address不能在给定的程序中重用,并且必须为每个新操作(在同一程序中(给出新的memory-address,是使用高深度recursion时内存溢出的原因吗?

我希望我已经把我的问题说清楚了。

如果我的理解在任何地方都是错误的,请纠正我。来自机械工程背景,虽然我已经编程了很长一段时间,但这件事对我来说真的很困惑。

问候

要理解正在发生的事情,一个简单的心理模型是

  1. 每个python变量都是一个指针。
    即使在 Python 内部i=1后,i也是一个指向包含值 1 的对象的指针。即使是整数也是普通对象(这并不常见,因为在其他语言中,通常变量最终会直接包含小整数的值(。

  2. 出于效率原因,缓存和共享一些不可变对象。
    小整数被缓存,因此在 Python 程序中,如果所有带有值的变量0将是指向同一对象的指针。 在第二种情况下,您观察到不同的id,因为值不同(i将指向 1,j将指向 2(。
    请注意,共享仅针对不可变对象执行,因为除非使用id否则无法在代码中观察到共享。在 Python 中,这是针对小数字和一些小字符串(那些最终被"拘留"的字符串(完成的。

使用dis查看引擎盖下发生的事情。

In [1]: import dis
In [2]: def swap(): a=1; b=2; a,b=b,a
In [3]: dis.dis(swap)
1           0 LOAD_CONST               1 (1)
2 STORE_FAST               0 (a)
4 LOAD_CONST               2 (2)
6 STORE_FAST               1 (b)
8 LOAD_FAST                1 (b)
10 LOAD_FAST                0 (a)
12 ROT_TWO
14 STORE_FAST               0 (a)
16 STORE_FAST               1 (b)
18 LOAD_CONST               0 (None)
20 RETURN_VALUE

在 Python 中,变量是内存引用。 创建时

a=2

Python 内存管理器将此值2放在内存堆插槽中,并将此内存插槽的地址分配给变量。本质上

a=adress_of_this_memory_slot

在后台,每当您调用a时,python 内存管理器都会查看地址并检索值。

如果对象是不可变的,Python 内存管理器会自动重用内存引用。在您的情况下,整数是不可变的对象。所以python按需重用对象,这在python中被称为实习

在启动时,python 预加载或缓存 [-5,256] 范围内的整数的全局列表。每当在此范围内引用整数时,Python 将使用该对象的缓存版本。

因此,根据您的第一个示例,您创建了:

a=2
b=3

因此,python内存管理器会将这些值添加到两个不同的内存堆插槽中。 在您的示例中,它们的地址是:

id(a) ==> 140732857872688 
id(b) ==> 140732857872720

在此之后,任何时候你想使用int 2,3python都会使用此内存地址进行优化。

尝试使用超出此范围的整数 [-5,256] 的示例。 您将看到 Python 将为此变量重新创建一个新地址,换句话说,Python 不会共享这些值的引用。

最新更新