[Python-Dev] Simpler finalization semantics (was Re: PEP 343 - Abstract Block Redux)

Nick Coghlan ncoghlan at gmail.com
Thu May 19 11:50:50 CEST 2005


Michael Chermside wrote:
> If I write
> 
>     with foo:
>        BLOCK
> 
> where I should have written
> 
>     with locked(foo):
>        BLOCK
> 
> ...it silently "succeeds" by doing nothing. I CLEARLY intended to
> do the appropriate cleanup (or locking, or whatever), but it doesn't
> happen.

Ah, thanks. Like Guido, I had something in the back of my head saying it didn't 
like the idea, but I couldn't figure out the reason. I think you just nailed it.

Plus, there is a nice alternative which is to provide a 'clean it up if it needs 
it' resource in the standard library:

   class resource(object):
       def __init__(self, obj):
           self.obj = obj
           self.enter = getattr(obj, "__enter__", None)
           self.exit = getattr(obj, "__exit__", None)

       def __enter__(self):
           if self.enter is not None:
               self.enter()
           # For consistency, always return the object
           return self.obj

       def __exit__(self, *exc_info):
           if self.exit is not None:
               self.exit(*exc_info)

Then 'I don't know if this needs cleaning up or not' can be written:

   with resource(foo):
       # If foo needs cleaning up, it will be.

A refinement would provide the option to specify the enter/exit methods directly:

   class resource(object):
       def __init__(self, obj, *other_args):
           self.obj = obj
           if other_args:
               if len(other_args) != 2:
                   raise TypeError("need 1 or 3 arguments")
               self.enter = args[0]
               self.exit = None
               self.exit_no_args = args[1]
           else:
               self.enter = getattr(obj, "__enter__", None)
               self.exit = getattr(obj, "__exit__", None)
               self.exit_no_args = None


       def __enter__(self):
           if self.enter is not None:
               self.enter()
           # For consistency, always return the object
           return self.obj

       def __exit__(self, *exc_info):
           if self.exit is not None:
              self.exit(*exc_info)
           elif self.exit_no_args is not None:
              self.exit()

That would let any object with a standard 'clean me up method' be easily used in 
a with statement:

   with resource(bar, None, bar.clear):
       # bar will be cleared when we're done

Cheers,
Nick.

-- 
Nick Coghlan   |   ncoghlan at gmail.com   |   Brisbane, Australia
---------------------------------------------------------------
             http://boredomandlaziness.blogspot.com


More information about the Python-Dev mailing list