Make a nested list:
In [8]: alist=[[1,2,3],[4,5]]
In [9]: len(alist)
Out[9]: 2
It's a list of 2 items; the items happen to be lists. In some sort meta view it is 2d, but nothing about the list itself is 2d.
Make an array from it:
In [10]: arr = np.array(alist)
In [11]: arr.shape
Out[11]: (2,)
In [12]: arr.dtype
Out[12]: dtype('O')
In [13]: arr
Out[13]: array([[1, 2, 3], [4, 5]], dtype=object)
In [14]: arr[0]
Out[14]: [1, 2, 3]
In [15]: type(arr[0])
Out[15]: list
It too has 2 elements, in fact the same 2 sublists as alist (same id)
In [16]: id(alist[0])
Out[16]: 2992863468
In [17]: id(arr[0])
Out[17]: 2992863468
If I change an element of one of those sublists, the change appears in the other structure
In [18]: arr[0][1]=3
In [19]: arr
Out[19]: array([[1, 3, 3], [4, 5]], dtype=object)
In [20]: alist
Out[20]: [[1, 3, 3], [4, 5]]
For most purposes an object array like this is just like a list. You can reshape it, eg. `arr.reshape(2,1)', but you can't append to it. And to perform most actions you (or numpy) has to iterate through the elements just as if it were a list.
Contrast that with a 2d array of integers
In [21]: A=np.array([[1,2,3],[4,5,6]])
In [22]: A
Out[22]:
array([[1, 2, 3],
[4, 5, 6]])
In [23]: A.shape
Out[23]: (2, 3)
In [24]: A.dtype
Out[24]: dtype('int32')
May be it will to visualize the object barrier if I change the elements of arr into arrays:
In [26]: arr[0]=np.array(arr[0])
In [27]: arr[1]=np.array(arr[1])
In [28]: arr
Out[28]: array([array([1, 3, 3]), array([4, 5])], dtype=object)
It is now an array of arrays; but that still not the same as a 2d array.
type(nFuncs[1])?shape?[1].