Exceptions and Object Destruction (was: Problem with apsw and garbage collection)

Mike Kazantsev mk.fraggod at gmail.com
Sun Jun 14 01:55:09 EDT 2009


On Fri, 12 Jun 2009 18:33:13 -0400
Nikolaus Rath <Nikolaus at rath.org> wrote:

> Nikolaus Rath <Nikolaus at rath.org> writes:
> > Hi,
> >
> > Please consider this example:
> [....]
> 
> I think I managed to narrow down the problem a bit. It seems that when
> a function returns normally, its local variables are immediately
> destroyed. However, if the function is left due to an exception, the
> local variables remain alive:
>
...
> 
> Is there a way to have the obj variable (that is created in dostuff())
> destroyed earlier than at the end of the program? As you can see, I
> already tried to explicitly call the garbage collector, but this does
> not help.

Strange thing is that no one suggested contextlib, which made _exactly_
for this purpose:


  #!/usr/bin/env python
  import gc

  class testclass(object):
    def __init__(self):
      self.alive = True # just for example
      print "Initializing"
    
    def __del__(self):
      if self.alive:
        # try..except wrapper would suffice here,
        # so destruction won't raise ex, if already done
        print "Destructing"
        self.alive = False

    def __enter__(self): pass
    def __exit__(self, ex_type, ex_val, ex_trace):
      self.__del__()
      if not ex_type is None:
        raise RuntimeError(ex_val)

  
  def dostuff(fail):
    with testclass() as obj:
      # some stuff
      if fail:
        raise TypeError
      # some more stuff
    print "success"

  
  print "Calling dostuff"
  dostuff(fail=False)
  print "dostuff returned"

  try:
    print "Calling dostuff"
    dostuff(fail=True)
  except TypeError:
    pass

  gc.collect()
  print "dostuff returned" 


And it doesn't matter where you use "with", it creates a volatile
context, which destructs before anything else happens on higher level.

Another simplified case, similar to yours is file objects:


  with open(tmp_path, 'w') as file:
    # write_ops
  os.rename(tmp_path, path)

So whatever happens inside "with", file should end up closed, else
os.rename might replace valid path with zero-length file.

It should be easy to use cursor with contextlib, consider using
contextmanager decorator:


  from contextlib import contextmanager

  @contextmanager
  def get_cursor():
    try:
      cursor = conn.cursor()
      yield cursor
    except Exception as ex: raise ex
    finally: cursor.close()
    
  with get_cursor() as cursor:
    # whatever ;)



-- 
Mike Kazantsev // fraggod.net
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 205 bytes
Desc: not available
URL: <http://mail.python.org/pipermail/python-list/attachments/20090614/c323fd4f/attachment-0001.sig>


More information about the Python-list mailing list