1
votes

I have a use-case that resembles the following:

files = [open("foo1.pdf", "rb"), open("foo2.pdf", "rb"), open("foo3.pdf", "rb")]
# ... extract portions from the opened files using PyPDF2 and assemble a new PDF file
map(close, files)

Why I do that above? because while using PyPDF2 to merge multiple input PDF files into another file, if you close each input PDF you get empty pages in the output PDF. The input files have to stay open until the output PDF file is generated see https://github.com/mstamy2/PyPDF2/issues/293

Results in the following error:

NameError: name 'close' is not defined

The following works but I'd like the less verbose code variation:

map(lambda file: file.close(), files)

I'd of course prefer the following instead:

map(close, files)
2
Your are not calling the close method, but some non-existing close function that would be used like close(f). - Thierry Lathuille
You might want to take a look at contextlib.ExitStack which closes the files automatically for you. - a_guest
@a_guest thank you so much! very nice comment :) plz promote to answer and I'll happily accept. - SkyWalker
@SkyWalker The question is marked as a duplicate, so it cannot be answered at the moment. - a_guest
Please vote to reopen, it makes no sense to mark as duplicate for that other one ... it's a bot close warmongering :D - SkyWalker

2 Answers

3
votes

Because close is, by itself, not a function, unlike open. Instead, it is a method of a file-like object.

If you want to programmatically close files, you can call close using the objects themselves.

for x in files:
    x.close()

If you absolutely want to use map, you could use lambda function to do so, but I 'd recommend against that because map defines a generator, and hence it is unclear to the user which files are closed and which are open.

map(lambda x: x.close(), files)
1
votes

Use contextlib.ExitStack to open your files and ensure that they are properly closed.

from contextlib import ExitStack

names = ["foo1.pdf", "foo2.pdf", "foo3.pdf"]
with ExitStack() as es:
    files = [es.enter_context(open(f, "rb")) for f in names]
    # ... extract portions from the opened files using PyPDF2 and assemble a new PDF file

# proceed with the new PDF file