Truly recursive `tolist()` for NumPy structured arrays
<p>From what I understand, the recommended way to convert a NumPy array into a native Python list is to use <a href="http://docs.scipy.org/doc/numpy/reference/generated/numpy.ndarray.tolist.html" rel="nofollow"><code>ndarray.tolist</code></a>.</p>

<p>Alas, this doesn't seem to work recursively when using structured arrays. Indeed, some <code>ndarray</code> objects are being referenced in the resulting list, unconverted:</p>

<pre><code>&gt;&gt;&gt; dtype = numpy.dtype([('position', numpy.int32, 3)])
&gt;&gt;&gt; values = [([1, 2, 3],)]
&gt;&gt;&gt; a = numpy.array(values, dtype=dtype)
&gt;&gt;&gt; a.tolist()
[(array([1, 2, 3], dtype=int32),)]
</code></pre>

<p>I did write a simple function to workaround this issue:</p>

<pre><code>def array_to_list(array):
    if isinstance(array, numpy.ndarray):
        return array_to_list(array.tolist())
    elif isinstance(array, list):
        return [array_to_list(item) for item in array]
    elif isinstance(array, tuple):
        return tuple(array_to_list(item) for item in array)
    else:
        return array
</code></pre>

<p>Which, when used, provides the expected result:</p>

<pre><code>&gt;&gt;&gt; array_to_list(a) == values
True
</code></pre>

<p>The problem with this function is that it duplicates the job of <code>ndarray.tolist</code> by recreating each list/tuple that it outputs. Not optimal.</p>

<p>So the questions are:</p>

<ul>
<li>is this behaviour of <code>ndarray.tolist</code> to be expected?</li>
<li>is there a better way to make this happen?</li>
</ul>

<p>Just to generalize this a bit, I'll add  an another field to your dtype</p>

<pre><code>In [234]: dt = numpy.dtype([('position', numpy.int32, 3),('id','U3')])

In [235]: a=np.ones((3,),dtype=dt)
</code></pre>

<p>The <code>repr</code> display does use lists and tuples:</p>

<pre><code>In [236]: a
Out[236]: 
array([([1, 1, 1], '1'), ([1, 1, 1], '1'), ([1, 1, 1], '1')], 
  dtype=[('position', '&lt;i4', (3,)), ('id', '&lt;U3')])
</code></pre>

<p>but as you note, <code>tolist</code> does not expand the elements.</p>

<pre><code>In [237]: a.tolist()
Out[237]: [(array([1, 1, 1]), '1'), (array([1, 1, 1]), '1'), 
   (array([1, 1, 1]), '1')]
</code></pre>

<p>Similarly, such an array can be created from the fully nested lists and tuples.</p>

<pre><code>In [238]: a=np.array([([1,2,3],'str')],dtype=dt)
In [239]: a
Out[239]: 
array([([1, 2, 3], 'str')], 
  dtype=[('position', '&lt;i4', (3,)), ('id', '&lt;U3')])
In [240]: a.tolist()
Out[240]: [(array([1, 2, 3]), 'str')]
</code></pre>

<p>There's no problem recreating the array from this incomplete recursion:</p>

<pre><code>In [250]: np.array(a.tolist(),dtype=dt)
Out[250]: 
array([([1, 2, 3], 'str')], 
      dtype=[('position', '&lt;i4', (3,)), ('id', '&lt;U3')])
</code></pre>

<p>This is the first that I've seen anyone use <code>tolist</code> with a structured array like this, but I'm not too surprised.  I don't know if developers would consider this a bug or not. </p>

<p>Why do you need a pure list/tuple rendering of this array?  </p>

<p>I wonder if there's a function in <code>numpy/lib/recfunctions.py</code> that addresses this.</p>

python numpy structured-array