urlopen, six, and py2

Matt Wheeler m at funkyhat.org
Wed Mar 2 09:35:20 EST 2016


On 2 March 2016 at 14:05, Fabien <fabien.maussion at gmail.com> wrote:
> [snip]
> My question is: why does the python3 version need a "with" block while the
> python2 version doesn't? Can I skip the "with" entirely, or should I rather
> do the following:

It's not a case of "need", using the "with" construction is an added
feature, not a burden!

> from six.moves.urllib.request import urlopen
>
> try:
>     with urlopen('http://www.google.com') as resp:
>         _ = resp.read()
> except AttributeError:
>     # python 2
>     resp = urlopen('http://www.google.com')
>     _ = resp.read()

This is poor practise as you aren't closing "resp".
This leaves state lying around that you don't need anymore, which is
the whole purpose of the context manager that 3 provides.
It will *usually* be cleaned up when leaving the current scope, but
won't if there is an exception thrown. Using the context manager
ensures resp is *always* cleaned up properly even if an exception is
thrown.

I agree that six should probably handle this, but in the meantime you
could use contextlib.closing ([1]) rather than rolling your own. It
even uses urlopen as an example.

If you absolutely want to roll your own then don't bother with the
context manager provided by 3 at all, just use:

resp = urlopen('http://www.google.com')
try:
    _ = resp.read()
finally:
    resp.close()

But as this is wordier and more fragile than using a context manager
to clean up for you, I expect you won't bother :).


[1] https://docs.python.org/2/library/contextlib.html#contextlib.closing

-- 
Matt Wheeler
http://funkyh.at



More information about the Python-list mailing list