0

I've seen this syntax while dealing with the Python requests library:

body = { file_name: open(file_path, 'rb') }

I wonder if this closes the file as I've seen it written like this multiple times.

Gino Mempin
  • 25,369
  • 29
  • 96
  • 135
Niki
  • 738
  • 8
  • 17
  • Does this answer your question? [Is explicitly closing files important?](https://stackoverflow.com/questions/7395542/is-explicitly-closing-files-important) – oittaa Apr 13 '20 at 23:33
  • 1
    The question asks whether it is important to close files and the top answer basically states "yes, to flush data to disk". I may be wrong, but I don't think this answers my particular case. – Niki Apr 13 '20 at 23:41
  • 3
    It basically does: When the file object returned by `open()` has no more references to it the file will be closed. In this case a reference is held by the dictionary, but likewise when there are no references to the dictionary remaining it will also drop the reference to the file when it goes out of scope. This can potentially lead to bugs, with file handles being left open. Python 3 will warn about this if you run with `python -Wall`. For read-only files it's mostly harmless since there's no data to flush to disk. But I still would avoid this. – Iguananaut Apr 14 '20 at 00:06
  • 1
    @Iguananaut Thank you, this is exactly the answer I was hoping for. I also didn't know Python had a -Wall switch. If you would like you can post this as an answer so I can accept it. – Niki Apr 14 '20 at 01:29

1 Answers1

1

Re-posting my comment as accepted answer:

It basically does: When the file object returned by open() has no more references to it the file will be closed. In this case a reference is held by the dictionary, but likewise when there are no references to the dictionary remaining it will also drop the reference to the file when it goes out of scope. This can potentially lead to bugs, with file handles being left open. Python 3 will warn about this if you run with python -Wall. For read-only files it's mostly harmless since there's no data to flush to disk. But I still would avoid this.

For example:

$ python3 -Wall
Python 3.6.9 (default, Nov  7 2019, 10:44:02) 
[GCC 8.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> {'f': open('.bashrc')}
{'f': <_io.TextIOWrapper name='.bashrc' mode='r' encoding='UTF-8'>}
>>> exit()
sys:1: ResourceWarning: unclosed file <_io.TextIOWrapper name='.bashrc' mode='r' encoding='UTF-8'>

Actually you don't even need the dict for this:

$ python3 -Wall
Python 3.6.9 (default, Nov  7 2019, 10:44:02) 
[GCC 8.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> open('.bashrc')
<_io.TextIOWrapper name='.bashrc' mode='r' encoding='UTF-8'>
>>> exit()
sys:1: ResourceWarning: unclosed file <_io.TextIOWrapper name='.bashrc' mode='r' encoding='UTF-8'>

this is because in the last case, the last returned value in the REPL is stored in the special variable _.

In fact, this ResourceWarning will be raised any time the file object's __del__ is called before it's been explicitly closed:

$ python3 -Wall
Python 3.6.9 (default, Nov  7 2019, 10:44:02) 
[GCC 8.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> f = open('.bashrc')
>>> del f
__main__:1: ResourceWarning: unclosed file <_io.TextIOWrapper name='.bashrc' mode='r' encoding='UTF-8'>

This is only a warning (and disabled by default) since it's not generally a serious problem, as the file will still be closed. But it could indicate a bug, but so it's good to enable this warning when debugging file I/O issues, and also to open files using the with statement as general good practice:

>>> with open(file_path, 'rb') as fobj:
...     body = { file_name: fobj }
...     # send request, etc...
Niki
  • 738
  • 8
  • 17
Iguananaut
  • 21,810
  • 5
  • 50
  • 63