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
.)
\0
is still there but it's not printed (checkNULL
terminated strings). 2. They were probably developed in parallel (I remember that at 1st, ctypes was not in Python standard library). The functionality does partially overlap. Removing one such module would break backwards compatibility as there is probably lots of code out there that depends on each of the 3 modules. Note: ctypes uses struct. – Admassstruct
version, though! Also:len(c) == 12
,len(s.c) == 11
. 2. Well, Python did a lot of backwards-incompatible changes in the transition to Python 3. As far as I know, these kinds of “warts”/redundancies are exactly what they wanted to get rid of with Python 3. – Scheer\0
is encountered – Admass