title: Python: Similar functionality in struct and array vs ctypes
body: <p>Python provides the following three modules that deal with C types and how to handle them:</p>
  
  <ul>
  <li><a href="https://docs.python.org/3/library/struct.html" rel="noreferrer"><code>struct</code></a> for C structs</li>
  <li><a href="https://docs.python.org/3/library/array.html" rel="noreferrer"><code>array</code></a> for arrays such as those in C</li>
  <li><a href="https://docs.python.org/3/library/ctypes.html" rel="noreferrer"><code>ctypes</code></a> for C functions, which necessarily entails dealing with C’s type system</li>
  </ul>
  
  <p>While <code>ctypes</code> seems more general and flexible (its main task being “a foreign function library for Python”) than <code>struct</code> and <code>array</code>, 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</p>
  
  <pre><code>struct MyStruct {
      int a;
      float b;
      char c[12];
  };
  </code></pre>
  
  <p>I could use <code>struct</code> as follows:</p>
  
  <pre><code>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'
  </code></pre>
  
  <p>On the other hand, <a href="https://stackoverflow.com/a/1972348">using <code>ctypes</code> works equally well</a> (although a bit more verbose):</p>
  
  <pre><code> 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'
  </code></pre>
  
  <p>(Aside: I do wonder where the trailing <code>'\0'</code> went in this version, though…)</p>
  
  <p>This seems to me like it violates the principles in “The Zen of Python”:</p>
  
  <blockquote>
    <ol start="16">
    <li>There should be one—and preferably only one—obvious way to do it.</li>
    </ol>
  </blockquote>
  
  <p>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 <code>struct</code> module entirely and simply adding a more convenient API for reading/writing C structs to <code>ctypes</code>.)</p>