Say I have a function func(i) that creates an object for an integer i, and N is some nonnegative integer. Then what’s the fastest way to create a list (not a range) equal to this list
mylist = [func(i) for i in range(N)]
without resorting to advanced methods like creating a function in C? My main concern with the above list comprehension is that I’m not sure if python knows beforehand the length of range(N) to preallocate mylist, and therefore has to incrementally reallocate the list. Is that the case or is python clever enough to allocate mylist to length N first and then compute it’s elements? If not, what’s the best way to create mylist? Maybe this?
mylist = [None]*N
for i in range(N): mylist[i] = func(i)
RE-EDIT: Removed misleading information from a previous edit.
Somebody wrote: “””Python is smart enough. As long as the object you’re iterating over has a
__len__or__length_hint__method, Python will call it to determine the size and preallocate the array.”””As far as I can tell, there is no preallocation in a list comprehension. Python has no way of telling from the size of the INPUT what the size of the OUTPUT will be.
Look at this Python 2.6 code:
It just builds an empty list, and appends whatever the iteration delivers.
Now look at this code, which has an ‘if’ in the list comprehension:
The same code, plus some code to avoid the LIST_APPEND.
In Python 3.X, you need to dig a little deeper:
It’s the same old schtick: start off with building an empty list, then iterate over the iterable, appending to the list as required. I see no preallocation here.
The optimisation that you are thinking about is used inside a single opcode e.g. the implementation of
list.extend(iterable)can preallocate ifiterablecan accurately report its length.list.append(object)is given a single object, not an iterable.