Python中的临时引用会自动清除吗?
这个问题主要是关于临时对象的生命周期。如果一个函数返回了一个对象,但这个对象的引用没有被赋值给一个变量,只是用来调用返回对象的方法,那么这个临时引用会自动被清除吗?
举个具体的例子,假设有这样一串方法调用:
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 个回答
我想这个对象被加入到Python的垃圾回收器中,是因为它没有任何引用。然后这个对象就会被立刻删除。
你说的“清除”是什么意思呢?你可能是指“析构函数 __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
没错,垃圾回收器负责跟踪引用计数。当引用计数降到零时,垃圾回收器就会删除这个对象。下面是一个简单的例子。
>>> 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>
另外,如果有其他对象引用了这个临时对象,那么它就不会被删除。只有当引用计数为零时,这个对象才会被垃圾回收。
还有一点要提到的是 del
。del
只是减少了对象的引用计数,并不会真正“删除”这个对象。举个例子,如果 a = b = C()
,那么 del a
只是去掉了名字 a,并减少了对象 C()
的引用计数,但并没有真正删除它,因为 b
仍然在引用这个对象。
你说得对,引用计数是 CPython 的一种实现。至于其他实现,Python 的规范并没有保证对象什么时候会被销毁。
这是 Python 语言参考 对此的说明:
对象不会被明确地销毁;但是,当它们变得不可达时,可能会被垃圾回收。实现可以推迟垃圾回收或完全省略它——垃圾回收的实现质量取决于具体实现,只要没有收集到仍然可达的对象。