Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.python > #17601

Re: nesting context managers

References <ash6s8-qj5.ln1@satorlaser.homedns.org> <nbr6s8-n86.ln1@satorlaser.homedns.org> <CALwzidnGdNhfCAiGSAzU6bASCRdof_VGZAL_MCzGx0+dFUKb4A@mail.gmail.com>
From Ian Kelly <ian.g.kelly@gmail.com>
Date 2011-12-20 11:55 -0700
Subject Re: nesting context managers
Newsgroups comp.lang.python
Message-ID <mailman.3875.1324407391.27778.python-list@python.org> (permalink)

Show all headers | View raw


On Tue, Dec 20, 2011 at 11:46 AM, Ian Kelly <ian.g.kelly@gmail.com> wrote:
> On Tue, Dec 20, 2011 at 9:56 AM, Ulrich Eckhardt
> <ulrich.eckhardt@dominolaser.com> wrote:
>> Am 20.12.2011 15:15, schrieb Ulrich Eckhardt:
>>
>>> Let us assume I had a class HTTPClient that has a socket for HTTP and a
>>> logfile for filing logs. I want to make this HTTPClient a context
>>> manager, so that I can write
>>>
>>> with HTTPClient(url) as client:
>>>    pass
>>
>>
>> Actually, I overestimated the task:
>>
>>  class HTTPClient(url):
>>      def __enter__(self):
>>          return self
>>      def __exit__(self, ctx_type, ctx_val, ctx_tb):
>>          self.close()
>>      def close(self):
>>          self._myfile.close()
>>          self._mysocket.close()
>>
>> I'll simply ignore the fact that closing a file can fail if you can't flush
>> buffers. Now, my error was that I have to somehow invoke the file's and
>> socket's enter function in my client's enter function. The default for all
>> files and sockets is that they are already open, they are not opened in the
>> enter function! That way, the client remains usable outside a with context
>> but gives me the desired guarantees inside one.
>>
>> For the case of on-demand allocated stuff, I could write the enter function
>> like this:
>>
>>  def __enter__(self):
>>      # allocate resources
>>      f = ... # open file
>>      s = ... # connect socket
>>      # attach after completion
>>      self._myfile = f
>>      self._mysocket = s
>>
>> To be extra safe or in more complicated scenarios, I could wrap this in a
>> try-except and explicitly close those that were already created, but
>> normally I'd expect the garbage collector to do that for me ... or am I then
>> implicitly assuming a specific implementation?
>
> For full generality, copy the code for the contextlib.nested function
> in Python 2.7 or 3.1 and use that.  Don't use contextlib.nested
> itself, though, because it's deprecated and does not exist in Python
> 3.2.

Also note that in versions that do support the nested with syntax, you
can do something like:

class HTTPClient(url):
    @contextlib.contextmanager
    def _contextmanager(file, socket):
        with file, socket:
            yield
    def __enter__(self):
        self._cm = self._contextmanager(self._myfile, self._mysocket)
        return self._cm.__enter__()
    def __exit__(self, exc_type, exc_value, traceback):
        try:
            return self._cm.__exit__(exc_type, exc_value, traceback)
        finally:
            del self._cm

Cheers,
Ian

Back to comp.lang.python | Previous | NextPrevious in thread | Find similar | Unroll thread


Thread

nesting context managers Ulrich Eckhardt <ulrich.eckhardt@dominolaser.com> - 2011-12-20 15:15 +0100
  Re: nesting context managers Rami Chowdhury <rami.chowdhury@gmail.com> - 2011-12-20 16:25 +0000
  Re: nesting context managers Ulrich Eckhardt <ulrich.eckhardt@dominolaser.com> - 2011-12-20 17:56 +0100
    Re: nesting context managers Rami Chowdhury <rami.chowdhury@gmail.com> - 2011-12-20 17:46 +0000
    Re: nesting context managers Ian Kelly <ian.g.kelly@gmail.com> - 2011-12-20 11:46 -0700
    Re: nesting context managers Ethan Furman <ethan@stoneleaf.us> - 2011-12-20 10:02 -0800
    Re: nesting context managers Ian Kelly <ian.g.kelly@gmail.com> - 2011-12-20 11:55 -0700

csiph-web