Python中的临时引用会自动清除吗?

5 投票
3 回答
2151 浏览
提问于 2025-04-17 11:17

这个问题主要是关于临时对象的生命周期。如果一个函数返回了一个对象,但这个对象的引用没有被赋值给一个变量,只是用来调用返回对象的方法,那么这个临时引用会自动被清除吗?

举个具体的例子,假设有这样一串方法调用:

o.method_a().method_b()

当调用 method_b() 完成时,o.method_a() 返回的临时引用会自动被清除吗?就好像这一行是这样写的:

tmp = o.method_a()
try:
    tmp.method_b()
finally:
    tmp = None

我想知道一个普遍的答案。CPython 会在对象的引用计数降到 0 时立即清理对象。其他的 Python 实现可能不会立即清理对象。

我在想,Python 语言是否像 C++ 一样,保证临时对象在创建它们的语句结束时被销毁(只不过在 Python 中,问题是临时引用是否在创建它们的语句结束时被清除)。

在 C++ 中,类似的代码可能会这样实现:

class B {
public:
    void method_b();
};

class A {
public:
    std::shared_ptr<B> method_a();
};



A o;
o.method_a()->method_b();

C++ 标准指出:“临时对象在评估完整表达式的最后一步被销毁……这个表达式(在词法上)包含了它们被创建的点。即使这个评估以抛出异常结束,这也是正确的。”在这个例子中,这意味着通过调用 A::method_a() 创建的临时 std::shared_ptr<B> 对象会在评估完整表达式 o.method_a()->method_b(); 的最后立即被销毁。销毁一个 std::shared_ptr 意味着清除对共享对象的引用。

3 个回答

0

我想这个对象被加入到Python的垃圾回收器中,是因为它没有任何引用。然后这个对象就会被立刻删除。

2

你说的“清除”是什么意思呢?你可能是指“析构函数 __del__ 被调用了”,或者是指“相关的内存被释放了”。但这两者都没有保证会发生。举个例子,你可以把 CPython 2.7.2 和 PyPy 1.7.0 做个对比,看看 @Praveen Gollakota 提到的例子:

class C(object):
     def foo(self):
         return B()

class B(object):
    def __del__(self):
        print 'deleting %r' %self
    def bar(self):
        print 'I am method bar of %r' %self

c = C()
c.foo().bar()

print 'END OF LINE'

会产生

localhost-2:coding $ python tempref.py
I am method bar of <__main__.B object at 0x1004b7d90>
deleting <__main__.B object at 0x1004b7d90>
END OF LINE
localhost-2:coding $ pypy tempref.py
I am method bar of <__main__.B object at 0x0000000102bc4cb0>
END OF LINE
3

没错,垃圾回收器负责跟踪引用计数。当引用计数降到零时,垃圾回收器就会删除这个对象。下面是一个简单的例子。

>>> class C(object):
...     def foo(self):
...          return B()
... 
>>> class B(object):
...     def __del__(self):
...         print 'deleting %r' %self
...     def bar(self):
...         print 'I am method bar of %r' %self
... 
>>> c = C()
>>> c.foo().bar()
I am method bar of <__main__.B object at 0xa187d2c>
deleting <__main__.B object at 0xa187d2c>

另外,如果有其他对象引用了这个临时对象,那么它就不会被删除。只有当引用计数为零时,这个对象才会被垃圾回收。

还有一点要提到的是 deldel 只是减少了对象的引用计数,并不会真正“删除”这个对象。举个例子,如果 a = b = C(),那么 del a 只是去掉了名字 a,并减少了对象 C() 的引用计数,但并没有真正删除它,因为 b 仍然在引用这个对象。

你说得对,引用计数是 CPython 的一种实现。至于其他实现,Python 的规范并没有保证对象什么时候会被销毁。

这是 Python 语言参考 对此的说明:

对象不会被明确地销毁;但是,当它们变得不可达时,可能会被垃圾回收。实现可以推迟垃圾回收或完全省略它——垃圾回收的实现质量取决于具体实现,只要没有收集到仍然可达的对象。

撰写回答