我有一个名为Door
的班级和一个名为Window
的班级。它是名为Furniture
的类的子类。我的程序读取excel文件,循环2次,第一次读/写关于门的一切,第二次关于窗口。简化,我有以下代码:
for gathering_inf in ('door', 'window'):
for row in file:
if gathering_inf == 'door' and currently reading door line:
furniture = Door(width, height, description)
if gatherig_inf == 'window' and currently reading window line:
furniture = Window(width, height, description)
# Now do something with the furniture object ..
奇怪的想法发生的是,如果我(例如上图所示)打印对象furniture
,我得到它们的位置,并且内存中的一些对象的位置是相同的,即使它们是两个不同实例宽度不同的属性。例如:
<__main__.Door object at 0x03BFE810>
<__main__.Door object at 0x03BFE890>
<__main__.Door object at 0x03BFE810>
<__main__.Door object at 0x03BFE890>
<__main__.Door object at 0x03BFE8B0>
<__main__.Door object at 0x03BFE8D0>
<__main__.Door object at 0x03BFE8B0>
<__main__.Window object at 0x03BFE8D0>
<__main__.Window object at 0x03BFE8B0>
<__main__.Window object at 0x03BFE890>
<__main__.Window object at 0x03BFE8B0>
<__main__.Window object at 0x03BFE890>
<__main__.Window object at 0x03BFE8B0>
<__main__.Window object at 0x03BFE890>
<__main__.Window object at 0x03BFE8B0>
<__main__.Window object at 0x03BFE890>
有人可以向我解释为什么python会这样做吗?
答案 0 :(得分:4)
这是因为引用计数垃圾收集器。只要将新对象分配给furniture
,GC就会删除该对象,因此新对象可以重新使用其内存位置。
这是一个显示此行为的小型演示。请注意,由于Python REPL的工作方式(它保留对_
中最后一个结果的引用),地址将交替。
>>> foo = object(); foo
<object object at 0x7fd74cd390a0>
>>> foo = object(); foo
<object object at 0x7fd74cd390b0>
>>> foo = object(); foo
<object object at 0x7fd74cd390a0>
>>> foo = object(); foo
<object object at 0x7fd74cd390b0>
>>> foo = object(); foo
<object object at 0x7fd74cd390a0>
答案 1 :(得分:1)
ThiefMaster几乎把它钉了出来:这就是Python虚拟机的工作方式。
您正在观察的是引用计数垃圾收集器的 CPython 实现的细节。在你的情况下, CPython 是垃圾收集Door
对象,然后创建一个新的Window
对象,然后重用(现在垃圾收集)Door
对象的位置,将Window
对象存储在那里。
实际上看到 CPython 重用以前垃圾回收的对象的地址是很常见的。 例如,在我的计算机上运行ThiefMaster的代码我得到了稍微不同(旋转)的结果:
此时请务必注意此行为是CPython
特定的。例如,Enthought's Python Distribution似乎没有产生类似的结果,但我不知道这种不一致是否与实现差异有关: