Python 何时对返回值进行垃圾收集?

Python 何时对返回值进行垃圾收集?,python,garbage-collection,Python,Garbage Collection,我试图了解Python垃圾收集器是如何工作的,以及是否可以做些什么来控制对象的收集时间。我写了这个测试: >>> class Test: ... def __del__(self): ... print 'Delete ' + str(self) ... >>> def fun(): ... return Test() ... >>> fun() <__main__.Test instance at 0x0

我试图了解Python垃圾收集器是如何工作的,以及是否可以做些什么来控制对象的收集时间。我写了这个测试:

>>> class Test:
...     def __del__(self):
...         print 'Delete ' + str(self)
...
>>> def fun():
...    return Test()
...
>>> fun()
<__main__.Test instance at 0x0000000002989E48>
>>> fun()
Delete <__main__.Test instance at 0x0000000002989E48>
<__main__.Test instance at 0x00000000023E2488>
>>> fun()
Delete <__main__.Test instance at 0x00000000023E2488>
<__main__.Test instance at 0x0000000002989C48>
>类测试:
...     定义(自我):
...         打印“删除”+str(自身)
...
>>>def fun():
...    返回测试()
...
>>>乐趣
>>>乐趣
删除
>>>乐趣
删除

正如您所看到的,
Test
实例,虽然我没有保留一个实例,但直到下次调用
fun
时才会被删除。这仅仅是一个意外事件(可能在任何其他点被删除),还是只有在我再次调用
fun
时才会删除它的具体原因?如果我没有保留对它的引用,是否可以做些什么来确保它被删除?

尝试对返回值显式调用
del

returned_value = fun()
del returned_value
但是像
\uu del\uu
这样的终结器可能会有问题;正如您已经看到的,一个问题是,当它们被调用时是不确定的。此外,在终结器中还可以重新实例化已删除的对象,例如在全局列表中粘贴对该对象的引用

如果您需要释放资源(除了原始内存),例如解锁锁、关闭文件或释放数据库连接,请使用上下文管理器,并使用
with
语句绑定其生命周期。其中许多资源已经是上下文管理器。例如,可以使用
with
隐式锁定和解锁threading.Lock:

# "with" statement will call the __enter__ method of self.lock,
# which will block until self.lock can be locked
with self.lock:
    # do thread-synchronized stuff here

# self.lock is automatically released here - at then end of
# the "with" block, the lock's __exit__ method is called, which
# releases the lock. This will get called even if the block is 
# exited by a raised exception
Python垃圾收集器(与所有垃圾收集器一样)的“联系”在于,它将在最后一个可访问的对象引用消失后的某个时间释放该对象

因为CPython使用引用计数,作为一个实现细节,它将在最后一个可访问的引用消失后立即释放大多数垃圾对象(特别是非循环对象)。这不是Python语言的保证,对于PyPy、Jython、IronPython等其他Python实现也不是这样,因此依赖它通常被认为是不好的做法

在您的例子中,您在再次调用函数后观察到的对象与垃圾收集器的行为关系不大,而是由于交互式解释器shell的工作方式

在交互式提示中计算表达式时,生成的值将自动保存在变量
\uu
中,因此,如果您发现只有在看到打印后才需要它,则可以将其取回。因此,在调用
fun()
之后,仍然有一个对返回值的引用。然后,当您计算另一个表达式(其他任何表达式,它不必再次涉及
fun
)时,
\uu
将被新值覆盖,从而允许对旧表达式进行垃圾收集


这只发生在交互提示下直接输入的表达式上,因此不会延迟函数内对象的收集,也不会延迟Python代码作为脚本导入或运行。

类似于。
del fun()
是一个语法错误,这是正确的,因为这根本没有意义。我非常同意其余内容。@delnan我认为它
del
只是删除了对对象的引用,它何时被删除仍由GC决定。@PaulManta。这就是为什么它只适用于名称和集合项(<代码> DEFO(Bar)< /代码>)。谢谢代码< > DEL FUNTY()/<代码> -大脑上的C++太多了!