解释器环境中的python垃圾收集和uuu下划线

解释器环境中的python垃圾收集和uuu下划线,python,garbage-collection,Python,Garbage Collection,如果在解释器环境中定义了类: class C(object): def __init__(self, val): self.x = val 然后不使用名称进行实例化: >>> C(1) >>> C(2) >>> 然后我们可以用下划线来指代C(2),所以我的问题是: 既然下划线“u”指的是C(2),我们可以说是参考吗 C(2)的计数器仍然是1?因此python gc将不释放 C(2) 据我所知,在这些C(2)被执

如果在解释器环境中定义了类:

class C(object):
    def __init__(self, val):
        self.x = val
然后不使用名称进行实例化:

>>> C(1)
>>> C(2)
>>> 
然后我们可以用下划线来指代
C(2)
,所以我的问题是:

  • 既然下划线“u”指的是
    C(2)
    ,我们可以说是参考吗
    C(2)
    的计数器仍然是1?因此python gc将不释放
    C(2)
  • 据我所知,在这些
    C(2)
    被执行之后,没有名字会引用
    C(1)
    ,所以我可以说一旦
    C(2)
    被执行,
    C(1)
    python gc是否将释放内存
这实际上是4个问题,一个粗体字对应一个

gc:垃圾收集的缩写

编辑

让我通过直接对代码进行评论来更清楚地说明我的第一个问题

>>> C(1) # Press Enter Key and run
>>> 
>>> At Here, what is the exact reference count for the previous anonymous object "C(1)"? 
>>> And how to prove?
>>> 
>>> C(2) # Press Enter Key and run
>>> 
>>> At Here, what is the exact reference count for the previous anonymous object "C(1)"?
>>> And how to prove?

代码> C(1)<代码>或<代码> C(2)最后一行解释时,它们在中间或代码中的行为不同。

如果
C(1)
位于最后一行,python解释器将把它存储为
,因此实际上它将附加一个名称。如果选中实例数(C),结果将为1

如果
C(1)
不在最后一行,则该临时匿名对象将被销毁并消失

检查以下测试代码

您可以使用
numberofinstances
来显示内存中是否存在
C
对象

import gc

def name_of_instances(cls):
    return [obj for obj in gc.get_objects() if isinstance(obj, cls)]

def number_of_instances(cls):
    return len([obj for obj in gc.get_objects() if isinstance(obj, cls)])
1.匿名对象不在最后一行

In [12]: C(1)
    ...: C(2)
    ...: print(number_of_instances(C))
    ...:
0

In [13]:
In [6]: C(1)
Out[6]: <__main__.C at 0x6a97ba8>

In [7]: print(number_of_instances(C))
   ...: print(name_of_instances(C))
   ...:
1
[<__main__.C object at 0x0000000006A97BA8>]

In [8]: C(2)
Out[8]: <__main__.C at 0x6a9b518>

In [9]: print(number_of_instances(C))
   ...: print(name_of_instances(C))
   ...:
2
[<__main__.C object at 0x0000000006A97BA8>, <__main__.C object at 0x0000000006A9B518>]
In [13]: C(3)
Out[13]: <__main__.C at 0x6aa06d8>

In [14]: type(_)
Out[14]: __main__.C
2.最后一行的匿名对象

In [12]: C(1)
    ...: C(2)
    ...: print(number_of_instances(C))
    ...:
0

In [13]:
In [6]: C(1)
Out[6]: <__main__.C at 0x6a97ba8>

In [7]: print(number_of_instances(C))
   ...: print(name_of_instances(C))
   ...:
1
[<__main__.C object at 0x0000000006A97BA8>]

In [8]: C(2)
Out[8]: <__main__.C at 0x6a9b518>

In [9]: print(number_of_instances(C))
   ...: print(name_of_instances(C))
   ...:
2
[<__main__.C object at 0x0000000006A97BA8>, <__main__.C object at 0x0000000006A9B518>]
In [13]: C(3)
Out[13]: <__main__.C at 0x6aa06d8>

In [14]: type(_)
Out[14]: __main__.C
但在这种情况下,引用计数器从不计算
\uuu
中的引用,它只计算您未观察到的

这里有一个猜测:
\uu
不在
gc.garbage
列表中。如果连续运行
C(1)
print(实例数(C))
number\u\u\u实例
将不会签入
\u
,这可能存储了以前的
C(1)


请看:

@allen,非常感谢您的回答

根据您的猜测,我编写了以下代码:

In [3]: {'a': 1}
Out[3]: {'a': 1}

In [4]: C(1)
   ...: print(_)
   ...: print(type(_))
   ...: print(number_of_instances(C))
   ...:
{'a': 1}
<class 'dict'>
0

In [5]:
[3]中的
:{'a':1}
Out[3]:{'a':1}
In[4]:C(1)
…:打印()
…:打印(类型())
…:打印(实例的数量(C))
...:
{'a':1}
0
在[5]中:
因此uu下划线仅用于存储“单步模式”解释器中最后一个表达式的值,而不用于“连续模式”

这可能是初学者经常犯的错误


无论如何,非常感谢你的回答

是的,基本上是这样。您可以使用
sys.getrefcount
@juanpa.arrivillaga从经验上探索这一点。如果我再次运行sys.getrefcount(C(2)),我预计结果将是2,因为最后一个下划线引用了它。但结果是1。因此,我认为您的解释不够令人信服。
sys.getrefcount(C(2))
创建一个全新的
C
对象,将其传递给refcount,并且从不将其绑定到名称。从来没有超过一个。.@juanpa.arrivillaga除了使用下划线外,我如何确保C(2)仍然存在于内存中?我的意思是,有没有办法检查最后一个C(2)是否仍然保留一个refcount?@juanpa.arrivillaga我想我没有解释清楚我的问题。我修改了我的问题使它更清楚。谢谢!我有一个相关的问题,也许你会知道答案