Python provides the following three modules that deal with C types and how to handle them:
struct
for C structsarray
for arrays such as those in Cctypes
for 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
.)