Jan Bodnar Jan Bodnar - 23 days ago 7
Python Question

Python ftplib: How to correctly release connection object?

I have seen code like this (Python 3 code):

import ftplib
from contextlib import closing

with closing(ftplib.FTP()) as ftp:


Is the usage of the
closing
method necessary? In an interesting answer, we can read that in database connection objects the context manager's
__exit__
method does not close the connection (at least not for SQLite), but commits a transaction instead. Therefore, using the
closing
method is necessary.

How is it with the Python's FTP class?

Looking at the sources of the Python ftplib, we can find this:

# Context management protocol: try to quit() if active
def __exit__(self, *args):
if self.sock is not None:
try:
self.quit()
except (OSError, EOFError):
pass
finally:
if self.sock is not None:
self.close()


The
quit
method is called hence I think that we don't have to use the
closing
method for Python 3. So we can use just:

with (ftplib.FTP()) as ftp:


Since
__exit__
method is missing in Python 2,
closing
is necessary for Python 2 code.

Is this correct?

Answer Source

You did answer your own question for the most part.
And as per discussed in the comments, it's a legit question since the internet is "littered with incorrect code examples".

To clarify my short answer, this is a heritage issue where Python3 code won't perform as expected on Python2. So (good) examples on the internet will hopefully either include a explanation of the dangers of running the code in Python2.. Or they'll make the code backwards compatible with a small modification.

This is such a instance where closing() is used to emulate the new functions from Python3 when the code is run on Python2.

Python2 (ftplib) doesn't have either a __enter__ or a __exit__ function, thus rendering the context handle "useless" (except making it forward compatible, easier to read IMO and also it assigned the call to a variable, in this case ftp).
To make it un-useless the writer used closing() around the call to get the automatic closure as per Python3.

If you're souly using Python3, this is redundant and probably slows down your code (extremely little). And there for you can skip that particular piece of code if you're not looking to be backwards compatible.