urlopen, six, and py2

Chris Angelico rosuav at gmail.com
Wed Mar 2 09:53:05 EST 2016


On Thu, Mar 3, 2016 at 1:35 AM, Matt Wheeler <m at funkyhat.org> wrote:
>> 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.

Not sure why you say it won't if there's an exception thrown. This
code will do the same thing on both versions:

def get_data():
    resp = urlopen('http://www.google.com')
    return resp.read()

Absent the context manager, this depends on object disposal for its
cleanup. But whether this function returns normally or raises an
exception, the response object goes out of scope at the same time.
There's no guarantee that it'll be cleaned up immediately when the
function exits, but it's the same for the exceptional and
non-exceptional cases.

Agreed that try/finally is the best way to do cross-platform code here:

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

It's reasonably compact, and fairly clear. And it has the exact
guarantee that the context manager has (before the function exits, the
'finally' block will be performed, and resources will be properly
released).

ChrisA



More information about the Python-list mailing list