我写这篇文章是为了扩展我对pointers
和memory-addressing
如何在python
中工作的理解。
Python是一种高级语言,我了解到内存管理由python负责。
我还了解到指针可以用id()
对象来识别。
假设我有两个变量a
和b
,这两个变量可以用以下命令交换:
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
时内存溢出的原因吗?
我希望我已经把我的问题说清楚了。
如果我的理解在任何地方都是错误的,请纠正我。来自机械工程背景,虽然我已经编程了很长一段时间,但这件事对我来说真的很困惑。
问候
要理解正在发生的事情,一个简单的心理模型是
-
每个python变量都是一个指针。
即使在 Python 内部i=1
后,i
也是一个指向包含值 1 的对象的指针。即使是整数也是普通对象(这并不常见,因为在其他语言中,通常变量最终会直接包含小整数的值(。 -
出于效率原因,缓存和共享一些不可变对象。
小整数被缓存,因此在 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,3
python都会使用此内存地址进行优化。
尝试使用超出此范围的整数 [-5,256] 的示例。 您将看到 Python 将为此变量重新创建一个新地址,换句话说,Python 不会共享这些值的引用。