我正在玩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>
答案 0 :(得分:6)
您的问题涉及Python如何分配内存。 tldr; Python使用堆来存储内存。当资源被释放时,它会到达堆的顶部。
Python必须分配内存来创建对象的实例。为了提高内存效率,Python memory manager有一堆内存位置可用于为对象的实例化提供或保留。使用您的一些示例,您可以看到它在实践中是如何工作的。
>>> 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>
。等
>>> 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>
>>> 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对象是引用计数的,因此只要没有引用它们就会消失。
如果事情按照你期望的方式发挥作用,你可能会很快耗尽内存。