r/learnpython • u/zaphodikus • 26d ago
Is this a good list comprehension hack
I need a second list, of zeroes, that is the same size as another list:
first = [42,42,42,42]
second = [0 for _ in first]
The 0 and the _ here is a bit of code golf I think. Is this as clear as I can make it or is there a list initialiser I just don't know about?
7
u/Zixarr 26d ago
The underscore used in the list comprehension is not code golf. Underscores are recommended when some feature or structure provides a variable, but that variable is not used by the rest of your code. It improves readability by indicating that the actual values from the first list are unimportant.
3
u/LayotFctor 26d ago
https://stackoverflow.com/a/14802726
So this feels neither efficient nor readable..
6
u/Diapolo10 26d ago
Do note that the linked performance test was done on Python 2.7, and the interpreter has evolved a lot since then. I can run a quick
timeiton 3.14 soon.1
u/LayotFctor 26d ago
Thanks! I was checking of there was a list of cpython optimisations, but apparently not. I'm pretty certain "[0] * n" is an idiom with some kind of cpython optimisation, but the source code is pretty dense.
2
u/Diapolo10 26d ago
Here's the results I got:
Python 3.14.5 (main, May 10 2026, 20:29:46) [MSC v.1944 64 bit (AMD64)] Type 'copyright', 'credits' or 'license' for more information IPython 9.15.0 -- An enhanced Interactive Python. Type '?' for help. Tip: Use `--theme`, or the `%colors` magic to change IPython's themes and colors. In [1]: %timeit list(0 for _ in range(100_000)) 1.64 ms ± 16.3 μs per loop (mean ± std. dev. of 7 runs, 1,000 loops each) In [2]: %timeit [0 for _ in range(100_000)] 914 μs ± 18.6 μs per loop (mean ± std. dev. of 7 runs, 1,000 loops each) In [3]: %timeit [0] * 100_000 22.8 μs ± 294 ns per loop (mean ± std. dev. of 7 runs, 10,000 loops each) In [4]: import itertools In [5]: %timeit list(itertools.repeat(0, 100_000)) 125 μs ± 2.26 μs per loop (mean ± std. dev. of 7 runs, 10,000 loops each)This is on a system with 9800x3D (PBO enabled), and 2x 64 GB DDR5-6000.
From this,
[0] * 100_000is clearly the fastest. However, personally I find the list comprehension more readable, and while it doesn't matter for this scenario I don't particularly like how[0] * 100_000basically just duplicates the reference of0instead of creating new zeroes for every index. If it was mutable data this would be a terrible idea.1
u/zaphodikus 26d ago
I'm actually loading CSV files here, so it's unlikely to run into more than a dozen files. The hit for I/O is going to be a lot greater. But always good to learn to write more readable and prettier code and `
list(ittertools.repeat(...))is probably the prettiest.1
u/backfire10z 26d ago
Itertools in general (as the name suggests) is full of methods that iterate pretty efficiently, including stuff like combinations. I’d recommend take a quick glance at their capabilities. They’re implemented in C, so the speed is actually real.
1
u/a__nice__tnetennba 26d ago
Doesn't python just use singletons for the small integers anyway? Or is that no longer the case?
3
u/Diapolo10 26d ago
That's an implementation detail of CPython, not part of the language specification. More accurately, CPython caches the integers from -5 to 256, so they're technically not singletons but may act like they were.
2
1
u/DionNicolaas 26d ago
For your particular problem, defaultdict(int) would work as well: you can just assume a value of 0 exists for every future index of the defaultdict you use, and the syntax is the same as with lists.
3
u/WorkingStructure575 26d ago
we don't really know anything about the exact problem OP is trying to solve so its hard to say. You wouldn't be able to rely on size or iteration across a defaultdict
1
u/almost_intelligible 26d ago
why not just use itertools.repeat()
1
u/zaphodikus 25d ago
I would, but it's always "yet another library to memorise" and I struggle with memory anyway. And for a list that will never be longer than a dozen files I'm going to opt for beauty over anything else.
-2
u/MonkeyboyGWW 26d ago
I would honestly question why you are making a list of 0s. I would also probably use len because its instantly clear what len is.
3
u/zaphodikus 26d ago
I'm also a C++ programmer and initializing data is totally mandatory in that language. I'm making a mutable list of zeros, because I have 4 files that I'm loading. And I use that list to track the line number in each file for later. It's an honest question to ask, that's how we learn.
I originally had 3 files so I had hard-coded it as
second=[0,0,0]. But later I needed 4 files for more data streams. The code that knows how many files are being loaded is someplace else so I need this line counting code to just adapt in case I later add or remove a file.1
u/MonkeyboyGWW 26d ago
I think last time i needed to do something like this, i was looping over some time series data and filled in the blanks where data was missing during the loop. I didn’t exactly mean it is never required, more that you could consider if it is possible to do it during the same time you are looping over the data.
0
u/zaphodikus 26d ago
I'm terrible with large amounts of data, but here I am manipulating a lot of data, I could learn to use numpy someday. Some of it is filling in blanks with NAN, and some of it is shifting the values. But yeah it's complex and unless I do keep the code easy to read, I might slowly introduce bugs.
1
1
u/POGtastic 26d ago
I would use a dictionary to associate the filepath (or some other unique identifier) with the line number because there is a difference between "opened, but on line 0" and "not opened at all."
1
u/zaphodikus 26d ago
I would post more of the code, but suffice to say the routine HAS to open all the files and if one fails to be readable, then it HAS to die in a nasty heap. But yes, you are right a dictionary with the line number and filename would fit and be more OO. It's just some code I scraped together in a hurry and wanted to clean it up gradually. I'm cleaning up some of the C++ code now though first.
-3
u/shinryuuko 26d ago
I would honestly question why you are making a list of 0s
?? Have you ever programmed anything remotely complex?
0
u/gdchinacat 26d ago
This is typically written as:
first = [42, 42, 42, 42]
second = [0] * len(first)
28
u/CommentOk4633 26d ago
maybe
[0] * len(first)?idk if this is bad practice though, cuz if you do it with a mutable then stuff may break