Fastest way to pack a list of floats into bytes in python
Just tell struct
how many float
s you have. 100k floats takes about a 1/100th of a second on my slow laptop.
import randomimport structfloatlist = [random.random() for _ in range(10**5)]buf = struct.pack('%sf' % len(floatlist), *floatlist)
You can use ctypes, and have a double-array (or float array) exactly as you'd have in C , instead of keeping your data in a list. This is fair low level, but is a recommendation if you need great performance and if your list is of a fixed size.
You can create the equivalent of a Cdouble array[100];
in Python by doing:
array = (ctypes.c_double * 100)()
The ctypes.c_double * 100
expression yields a Python class for an array of doubles, 100 items long. To wire it to a file, you can just use buffer
to get its contents:
>>> f = open("bla.dat", "wb")>>> f.write(buffer(array))
If your data is already in a Python list, packing it into a double array may or may not be faster than calling struct
as in Agf's accepted answer - I will leave measuring which is faster as homework, but all the code you need is this:
>>> import ctypes>>> array = (ctypes.c_double * len(floatlist))(*floatlist)
To see it as a string, just do: str(buffer(array))
- the one drawback here is that you have to take care of float size (float vs double) and CPU dependent float type - the struct module can take care of this for you.
The big win is that with a float array you can still use the elements as numbers, by accessing then just as if it where a plain Python list, while having then readily available as a planar memory region with buffer
.
A couple of answers suggest
import structbuf = struct.pack(f'{len(floatlist)}f', *floatlist)
but the use of '*
' needlessly converts floatlist
to a tuple before passing it to struct.pack
. It's faster to avoid that, by first creating an empty buffer, and then populating it using slice assignment:
import ctypesbuf = (ctypes.c_double * len(floatlist))()buf[:] = floatlist
Other performance savings some people might be able to use:
- You can reuse an existing buffer by just doing the assignment again, without having to create a new buffer.
- You can modify parts of an existing buffer by assigning to the appropriate slice.