Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

cleanup after exceptions

0 views
Skip to first unread message

Pad...@linux.ie

unread,
Dec 18, 2003, 2:11:12 PM12/18/03
to
Hi,

I'm a little confused why objects
are not deleted after they go
out of scope due to an exception?

For e.g.

>>> import time
>>>
>>> def f():
>>> myfile=open("file.test","w")
>>> myfile.write("not flushed\n")
>>> exception=throw
>>>
>>> f()
>>> time.sleep(10)


The file is not written/closed until
the python interpreter exits.
The same thing applies to other objects.

cheers,
Pádraig.

Jp Calderone

unread,
Dec 18, 2003, 2:43:45 PM12/18/03
to pytho...@python.org
On Thu, Dec 18, 2003 at 07:11:12PM +0000, Pad...@Linux.ie wrote:
> Hi,
>
> I'm a little confused why objects
> are not deleted after they go
> out of scope due to an exception?

Because objects don't go out of scope. Only variables do. Objects remain
"alive" as long as there are any references to them.

>
> For e.g.
>
> >>> import time
> >>>
> >>> def f():
> >>> myfile=open("file.test","w")
> >>> myfile.write("not flushed\n")
> >>> exception=throw
> >>>
> >>> f()
> >>> time.sleep(10)
>
>
> The file is not written/closed until
> the python interpreter exits.
> The same thing applies to other objects.

In this case, the traceback still holds a reference to the frame from
which the exception was raised, which itself holds a reference to all the
locales from that function.

Calling sys.exc_clear() (possibly followed by gc.collect()) should force
the cleanup you expect.

Jp

Pad...@linux.ie

unread,
Dec 18, 2003, 3:09:02 PM12/18/03
to
Jp Calderone wrote:
> On Thu, Dec 18, 2003 at 07:11:12PM +0000, Pad...@Linux.ie wrote:
>
>>Hi,
>>
>>I'm a little confused why objects
>>are not deleted after they go
>>out of scope due to an exception?
>
>
> Because objects don't go out of scope. Only variables do. Objects remain
> "alive" as long as there are any references to them.
>
>
>>For e.g.
>>
>>
>>>>>import time
>>>>>
>>>>>def f():
>>>>> myfile=open("file.test","w")
>>>>> myfile.write("not flushed\n")
>>>>> exception=throw
>>>>>
>>>>>f()
>>>>>time.sleep(10)
>>
>>
>>The file is not written/closed until
>>the python interpreter exits.
>>The same thing applies to other objects.
>
>
> In this case, the traceback still holds a reference to the frame from
> which the exception was raised,

OK I can see that, but why doesn't a pass on the exception release it?
This is demonstrated with:

#!/usr/bin/env python

import time

class c:
def __del__(self):
print "del"

def f():
C=c()
exception=throw

try:
f()
except:
pass

time.sleep(3)


> which itself holds a reference to all the
> locales from that function.

don't know what you mean by this

>
> Calling sys.exc_clear()

This isn't in version 2.2.2 at least

> (possibly followed by gc.collect()) should force
> the cleanup you expect.

thanks,
Pádraig.

Pad...@linux.ie

unread,
Dec 18, 2003, 3:11:17 PM12/18/03
to
Jp Calderone wrote:
> On Thu, Dec 18, 2003 at 07:11:12PM +0000, Pad...@Linux.ie wrote:
>
>>Hi,
>>
>>I'm a little confused why objects
>>are not deleted after they go
>>out of scope due to an exception?
>
>
> Because objects don't go out of scope. Only variables do. Objects remain
> "alive" as long as there are any references to them.
>
>
>>For e.g.
>>
>>
>>>>>import time
>>>>>
>>>>>def f():
>>>>> myfile=open("file.test","w")
>>>>> myfile.write("not flushed\n")
>>>>> exception=throw
>>>>>
>>>>>f()
>>>>>time.sleep(10)
>>
>>
>>The file is not written/closed until
>>the python interpreter exits.
>>The same thing applies to other objects.
>
>
> In this case, the traceback still holds a reference to the frame from
> which the exception was raised

OK I can see that, but why doesn't a pass on the exception release it?
This is demonstrated with:

#!/usr/bin/env python

import time

class c:
def __del__(self):
print "del"

def f():
C=c()
exception=throw

try:
f()
except:
pass

time.sleep(3)


> which itself holds a reference to all the
> locales from that function.

don't know what you mean by this

>
> Calling sys.exc_clear()

This isn't in version 2.2.2 at least

> (possibly followed by gc.collect()) should force
> the cleanup you expect.

thanks,
Pádraig.

Peter Otten

unread,
Dec 18, 2003, 3:49:16 PM12/18/03
to
Jp Calderone wrote:

I tried out your recipe, but with no luck:

Python 2.3.2 (#1, Oct 21 2003, 10:03:19)
[GCC 3.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> class T:
... def __del__(self):
... print "now i'm gone"
...
>>> def f():
... t = T()
... raise Exception
...
>>> import sys, gc
>>> f()
Traceback (most recent call last):
File "<stdin>", line 1, in ?
File "<stdin>", line 3, in f
Exception
>>> sys.exc_clear()
>>> gc.collect()
0

The only way to clear the reference I've found so far is a bit unorthodox:

>>> raise Exception
now i'm gone
Traceback (most recent call last):
File "<stdin>", line 1, in ?
Exception

There seems to be some dark corner of the exception infrastructure that
exc_clear() doesn't touch.

However, I think it's about time to direct the OP to the solution of the
"real" problem, i. e. ensuring that a resource is released when an
exception occurs:

>>> def g():
... t = T()
... try:
... raise Exception
... finally:
... del t
...
>>> g()
now i'm gone
Traceback (most recent call last):
File "<stdin>", line 1, in ?
File "<stdin>", line 4, in g
Exception
>>>

Whether immediate garbage collection occurs, is an implementation detail.
The code will be more portable if try...finally is used in such cases.

Peter


Tim Peters

unread,
Dec 18, 2003, 3:06:23 PM12/18/03
to pytho...@python.org
[Pad...@Linux.ie]

> I'm a little confused why objects
> are not deleted after they go
> out of scope due to an exception?

Because they don't go out of scope then -- named locals are still accessible by crawling over the traceback information available via the sys module.

> For e.g.
>
> >>> import time
> >>>
> >>> def f():
> >>> myfile=open("file.test","w")
> >>> myfile.write("not flushed\n")
> >>> exception=throw
> >>>
> >>> f()
> >>> time.sleep(10)

At this point you can still get at myfile, because of the traceback info that still exists. You neglected to show us the

NameError: global name 'throw' is not defined

traceback produced if you actually run this. It's possible to recreate the entire call stack at the point of the exception from the traceback info, and from the call stack you can get to all the locals of all the functions on the call stack, so "myfile" is still reachable. See the docs for sys.exc_info().

Note that locals in Python have lexical scope but dynamic extent: this isn't like C or C++ in the latter respect. All objects stay alive in Python for as long as they're reachable by any means, and nothing is destroyed *just* because a function exits (not even the stack frame is necessarily destroyed then -- it *usually* is, but a traceback can keep it alive, and a generator "yield" statement keeps the frame alive deliberately).


Tim Peters

unread,
Dec 18, 2003, 4:09:13 PM12/18/03
to pytho...@python.org
[Peter Otten]
> ...

> There seems to be some dark corner of the exception infrastructure
> that exc_clear() doesn't touch.

It's probably just an artifact of running in interactive mode. Then you
also have to worry about sys.last_traceback (see the sys docs).


Peter Otten

unread,
Dec 19, 2003, 3:03:01 AM12/19/03
to
Tim Peters wrote:

>>> class T:
... def __del__(self):
... print "i'm gone"


...
>>> def f():
... t = T()
... raise Exception
...
>>> import sys

>>> f()
Traceback (most recent call last):
File "<stdin>", line 1, in ?
File "<stdin>", line 3, in f
Exception

>>> sys.last_traceback = None
i'm gone
>>>

You're right. No dark corners then...

Peter

0 new messages