0

I use the following code to read a file in a list

list = [line.rstrip('\n') for line in open(file)]

I have not closed the file manually, because I assume that Python does this with the garbage collector itself.

When I do testing (framework 'unittest') it warns me that the file is unclosed.

ResourceWarning: unclosed file <_io.TextIOWrapper name='test_resources/names.txt' mode='r' encoding='UTF-8'> return [line.rstrip('\n') for line in open(file)]

How do I close the file in a one-liner?

nullpointr
  • 524
  • 4
  • 18

4 Answers4

2

If you do it like that, you won't ever be able to close that file, because open(file) is an unnamed variable that goes out of scope when the comprehension ends. As you found out yourself, the assumption "garbage collector closes the file once the comprehension is done" is not quite true: the GC is not running deterministically and you should not rely on it doing the cleanup for you.

The correct way to do this is via a with statement:

with open(file) as fp:
  list = [line.rstrip('\n') for line in fp]
# file gets closed here in __exit__()
GPhilo
  • 18,519
  • 9
  • 63
  • 89
  • Not a one-liner though! 8-) – DirtyBit Apr 09 '19 at 11:30
  • True enough, but (aside from removing the newline and calling it a one-liner) there is no way to close the file inside the comprehension. My point is, the file should have never been opened there in the first place. – GPhilo Apr 09 '19 at 11:33
  • 1
    AFAIK the garbage collector *does* close the file, but you never know when the garbage collector will actually run, and it's better to close the file explicitly as soon as you no longer need it. The context manager makes it more obvious that a file is being opened (which might throw an exception), too. – Aran-Fey Apr 09 '19 at 11:33
  • @Aran-Fey I'm not saying the GC won't close the file, I'm just saying relying on that is wrong (as the warning in the test clearly shows). I'll improve the wording to make that clearer ;) – GPhilo Apr 09 '19 at 11:37
  • you can do `from contextlib import closing` and then `closing([line.rstrip('\n') for line in open(file, 'r')]).thing` – gold_cy Apr 09 '19 at 11:46
2

Strongly recommend pathlib, see more at: https://docs.python.org/3/library/pathlib.html

from pathlib import Path
ss = Path('/path/to/file').read_text().splitlines()
Waket Zheng
  • 5,065
  • 2
  • 17
  • 30
2

Using pathlib

Path(file).read_text().splitlines()

Using ilio:

contents = read('filename').splitlines()
DirtyBit
  • 16,613
  • 4
  • 34
  • 55
0

Reading and closing a file in a single line:

with open('output.txt') as fd: list = [line.rstrip() for line in fd]

But there's no good reason to format your code that way.

ldx.a.ldy.c
  • 687
  • 4
  • 9