不同的类实例使用相同的内存位置

时间:2016-11-09 19:47:44

标签: python

我正在玩pickle库,当我注意到有时候,不同的类实例位于同一个内存位置。

以下两个示例都展示了所述行为:

class DemoClass:
    def __init__(self):
        self.name = 'demoName'

#example 1
for i in range(3):
    print (DemoClass())

#example 2
[print(DemoClass()) for i in range(3)]

#Output for both example 1 and example 2
#Note that the memory locations are identical in the output
<__main__.DemoClass object at 0x00CEE610>
<__main__.DemoClass object at 0x00CEE610>
<__main__.DemoClass object at 0x00CEE610>

这对我来说非常令人吃惊,所以也许你可以解释为什么会发生这种情况

程序按我的预期行事的方式如下。

demo = [DemoClass() for i in range(3)]
for i in demo:
    print (i)

#Output
<__main__.DemoClass object at 0x01F7E630>
<__main__.DemoClass object at 0x01F7ED30>
<__main__.DemoClass object at 0x01F7E670>

3 个答案:

答案 0 :(得分:6)

您的问题涉及Python如何分配内存。 tldr; Python使用堆来存储内存。当资源被释放时,它会到达堆的顶部。

详细答案

Python必须分配内存来创建对象的实例。为了提高内存效率,Python memory manager有一堆内存位置可用于为对象的实例化提供或保留。使用您的一些示例,您可以看到它在实践中是如何工作的。

示例#1

>>> for i in range(3):
...     print DemoClass()
... 
<test.DemoClass instance at 0x288b248>
<test.DemoClass instance at 0x288b248>
<test.DemoClass instance at 0x288b248>

for循环的第一次迭代期间,python使用其当前堆中的第一个可用地址,即<0x288b248>,为DemoClass创建print的实例打电话。完成print命令后,将释放内存地址并返回堆顶部。在循环的下一次迭代期间,python利用第一个可用的内存地址,该地址也是地址<0x288b248>。等

示例#2

>>> for j in [DemoClass() for i in range(3)]:
...     print j
... 
<test.DemoClass instance at 0x288bcf8>
<test.DemoClass instance at 0x288b290>
<test.DemoClass instance at 0x288b638>

这里python生成一个列表然后迭代。创建列表需要为每个元素创建一个 new DemoClass实例。这将从堆中取出前三个地址。循环完成后,列表将从内存中释放,如果我们再次调用print(DemoClass),我们将发现python再次重用内存。

>>> print DemoClass()
<test.DemoClass instance at 0x288bcf8>

示例3(我的交替存储器分配示例)

>>> for i in xrange(4):
...     Demo = DemoClass()
...     print(Demo)
... 
<test.DemoClass instance at 0x288bcf8>
<test.DemoClass instance at 0x288b290>
<test.DemoClass instance at 0x288bcf8>
<test.DemoClass instance at 0x288b290>

在此示例中,每次Demo实例化为DemoClass的实例时,会将一段内存分配给Demo。但是,对print(Demo)的调用释放分配给Demo的内存。在下一个循环开始时,新的内存段分配给Demo,然后Demo覆盖,此时它的原始内存地址返回到堆顶部。然后,用于Demo的内存地址在两个内存地址之间交替。

答案 1 :(得分:4)

在前两个示例中,一旦对print的调用完成,该对象就不再有引用,因此可以在下次创建该类型的对象时重复使用。

在第二种情况下,所有实例都同时具有引用,因此必须是不同的。

我不会依赖来处理这种行为,例如:可能存在该对象的其他未引用实例。

答案 2 :(得分:3)

当一个物体不再存在时,其位置可立即重复使用 由于Python对象是引用计数的,因此只要没有引用它们就会消失。

如果事情按照你期望的方式发挥作用,你可能会很快耗尽内存。