我以前也遇到过这个问题,我明白它会让人困惑。这里有两个概念:有些数据结构是可变的,而另一些则不是
Python可以脱离指针工作。。。大多数时候
所以让我们考虑一个列表的例子(当您使用ints时,您意外地发现了interning和peepoole优化-稍后我将讨论这个问题)
所以让我们创建两个相同的列表(记住列表是可变的)In [42]: a = [1,2]
In [43]: b = [1,2]
In [44]: id(a) == id(b)
Out[44]: False
In [45]: a is b
Out[45]: False
请看,尽管列表是相同的,a和{}是不同的内存位置。现在,这是因为python计算[1,2],将其分配给一个内存位置,然后调用该位置a(或b)。python要检查每个分配的内存位置以查看[1,2]是否已经存在,并将b分配给与a相同的内存位置,这需要相当长的时间。
更不用说列表是可变的,也就是说,您可以执行以下操作:
^{pr2}$
看到了吗?a保存的值已更改,但内存位置没有更改。现在,如果一堆其他变量名被分配到同一个内存位置呢?!它们也会被改变,这是语言的一个缺陷。为了解决这个问题,python必须将整个列表复制到一个新的内存位置,因为我想更改a的值
即使是空列表也是如此:In [51]: a = []
In [52]: b = []
In [53]: a is b
Out[53]: False
In [54]: id(a) == id(b)
Out[54]: False
现在,让我们谈谈我说过的关于指针的东西:
假设你想要两个变量来讨论同一个内存位置。然后,您可以将第二个变量分配给第一个变量:In [55]: a = [1,2,3,4]
In [56]: b = a
In [57]: id(a) == id(b)
Out[57]: True
In [58]: a is b
Out[58]: True
In [59]: a[0]
Out[59]: 1
In [60]: b[0]
Out[60]: 1
In [61]: a
Out[61]: [1, 2, 3, 4]
In [62]: b
Out[62]: [1, 2, 3, 4]
In [63]: a.append(5)
In [64]: a
Out[64]: [1, 2, 3, 4, 5]
In [65]: b
Out[65]: [1, 2, 3, 4, 5]
In [66]: a is b
Out[66]: True
In [67]: id(a) == id(b)
Out[67]: True
In [68]: b.append(6)
In [69]: a
Out[69]: [1, 2, 3, 4, 5, 6]
In [70]: b
Out[70]: [1, 2, 3, 4, 5, 6]
In [71]: a is b
Out[71]: True
In [72]: id(a) == id(b)
Out[72]: True
看看那里发生了什么!a和{}都被分配到同一个内存位置。因此,您对其中一个所做的任何更改都将反映到另一个上。在
最后,让我们简单谈谈我之前提到的窥视孔。Python试图节省空间。因此,当它启动时,它会将一些小的东西加载到内存中(例如,小整数)。因此,当您将一个变量赋给一个小整数(比如5),python不必在将值分配给内存位置并为其分配变量名之前计算5(与列表中的情况不同)。因为它已经知道5是什么,并将其存储在某个内存位置,所以它所做的就是为该内存位置分配一个变量名。但是,对于更大的整数,情况不再是这样了:In [73]: a = 5
In [74]: b = 5
In [75]: id(a) == id(b)
Out[75]: True
In [76]: a is b
Out[76]: True
In [77]: a = 1000000000
In [78]: b = 1000000000
In [79]: id(a) == id(b)
Out[79]: False
In [80]: a is b
Out[80]: False