Python provides the following three modules that deal with C types and how to handle them:
structfor C structsarrayfor arrays such as those in Cctypesfor C functions, which necessarily entails dealing with C’s type system
While ctypes seems more general and flexible (its main task being “a foreign function library for Python”) than struct and array, there seems to be significant overlap in functionality between these three modules when the task is to read binary data structures. For example, if I wanted to read a C struct
struct MyStruct {
int a;
float b;
char c[12];
};
I could use struct as follows:
a, b, c = struct.unpack('if12s', b'\x11\0\0\0\x12\x34\x56\x78hello world\0')
print(a, b, c)
# 17 1.7378244361449504e+34 b'hello world\x00'
On the other hand, using ctypes works equally well (although a bit more verbose):
class MyStruct(ctypes.Structure):
_fields_ = [
('a', ctypes.c_int),
('b', ctypes.c_float),
('c', ctypes.c_char * 12)
]
s = MyStruct.from_buffer_copy(b'\x11\0\0\0\x12\x34\x56\x78hello world\0')
print(s.a, s.b, s.c)
# 17 1.7378244361449504e+34 b'hello world'
(Aside: I do wonder where the trailing '\0' went in this version, though…)
This seems to me like it violates the principles in “The Zen of Python”:
- There should be one—and preferably only one—obvious way to do it.
So how did this situation with several of these similar modules for binary data handling arise? Is there a historical or practical reason? (For example, I could imagine omitting the struct module entirely and simply adding a more convenient API for reading/writing C structs to ctypes.)