Edit/solution
Here's an example that more closely mimics my real problem, and a solution implementing the comment by jonrsharpe. Thanks!
import io
import heapq
# THIS DOES NOT WORK AS INTENDED
files = dict(f0=io.StringIO("first line\nsecond line"),
f1=io.StringIO("FIRST LINE\nSECOND LINE"))
iterators = ((line.split() + [fname] for line in f)
for fname, f in files.items())
list(heapq.merge(*iterators))
# [['FIRST', 'LINE', 'f0'],
# ['SECOND', 'LINE', 'f0'],
# ['first', 'line', 'f0'],
# ['second', 'line', 'f0']]
# THIS DOES WORK
files = dict(f0=io.StringIO("first line\nsecond line"),
f1=io.StringIO("FIRST LINE\nSECOND LINE"))
iterators = ((lambda x=fname: ((line.split() + [x]) for line in f))(fname)
for fname, f in files.items())
list(heapq.merge(*iterators))
# [['FIRST', 'LINE', 'f1'],
# ['SECOND', 'LINE', 'f1'],
# ['first', 'line', 'f0'],
# ['second', 'line', 'f0']]
Original question
How can I make the Python code below produce [(1, 0), (1, 1)]
instead of [(2, 0), (2, 1)]
? That is, I wish the result wasn't affected by changes to const
made after the definition of the iterator it
.
>>> const = 1
>>> var = range(2)
>>> it = ((const, i) for i in var)
>>> const = 2
>>> list(it)
[(2, 0), (2, 1)]
My real-world problem is to heapq.merge multiple files without keeping all their contents in memory. I'd like to programmatically generate iterators that report the file name together with each line of each file, e.g. ("file2.txt", "this is line 1")
. Currently, all my iterators end up reporting the same filename.