This is basically a question about the lifetime of temporaries. If a function returns an object, but the reference is not assigned to a variable and is only used to call a method on the returned object, is the temporary reference automatically cleared?
To give a concrete example, suppose there is this chain of method calls:
o.method_a().method_b()
Is the temporary reference returned by o.method_a()
automatically cleared when the call to method_b()
finishes, as if the line were written like:
tmp = o.method_a()
try:
tmp.method_b()
finally:
tmp = None
I am interested in a general answer. CPython finalizes objects as soon as the reference count drops to 0. Other Python implementations might not finalize objects immediately.
I am wondering if the Python language is like C++, which guarantees that temporary objects are destroyed at the end of the statement for which they were created (except that in Python, the question is whether temporary references are cleared at the end of the statement for which they were created).
In C++, similar code might be implemented with:
class B {
public:
void method_b();
};
class A {
public:
std::shared_ptr<B> method_a();
};
A o;
o.method_a()->method_b();
The C++ standard states "Temporary objects are destroyed as the last step in evaluating the full-expression ... that (lexically) contains the point where they were created. This is true even if that evaluation ends in throwing an exception." In this example, it means that the temporary std::shared_ptr<B>
object created by the call to A::method_a()
is destroyed immediately at the end of evaluation of the full-expression o.method_a()->method_b();
. Destroying a std::shared_ptr
means clearing a reference to the shared object.
Yes, garbage collector is in charge of keeping track of reference counts. When the reference count drops to zero, the garbage collector deletes the object. Here is a quick example.
>>> 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>
As a side note, if there is a reference to the temporary object from any other object, then it doesn't get deleted. The object is garbage collected only when the reference count is zero.
Also a note about del
. del
just drops the reference count of an object. It doesn't delete an object. For example, if a = b = C()
, del a
only removes the name a and drops the reference count for object C()
, but doesn't really delete it, because b
still refers to it.
You're right, reference counting is a CPython implementation. As far as other implementations go, Python specification doesn't offer any guarantees about when objects are destroyed.
This is what Python Language Reference has to say about the matter:
Objects are never explicitly destroyed; however, when they become unreachable they may be garbage-collected. An implementation is allowed to postpone garbage collection or omit it altogether — it is a matter of implementation quality how garbage collection is implemented, as long as no objects are collected that are still reachable.
What do you mean by "cleared"? You could mean cleared as in "the destructor __del__
is called", or cleared as in "the associated memory is freed". Neither is guaranteed. For example, you can compare CPython 2.7.2 with PyPy 1.7.0 [using the example of @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'
produces
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With