I like to use .__array_interface__ .
In [811]: x.__array_interface__ Out[811]: {'data': (149194496, False), 'descr': [('', '<f8')], 'shape': (4, 4), 'strides': None, 'typestr': '<f8', 'version': 3} In [813]: y.__array_interface__ Out[813]: {'data': (149194496, False), 'descr': [('', '<f8')], 'shape': (4, 4), 'strides': (8, 32), 'typestr': '<f8', 'version': 3} In [814]: x.strides Out[814]: (32, 8) In [815]: y.strides Out[815]: (8, 32)
Transposition was performed by changing the course. The reference data pointer is the same.
In [817]: q.__array_interface__ Out[817]: {'data': (165219304, False), 'descr': [('', '<f8')], 'shape': (16,), 'strides': None, 'typestr': '<f8', 'version': 3}
So the q data is a copy (another pointer). Strides (8,) means that its elements are accessed by moving from one f8 to another. But a x.reshape(16) is a representation of x - because its data can be obtained with a simple step 8 .
To access the source data in q order, he will need a 32 byte step 3 times (down x rows), then go back to the beginning and step 8 in the second column x , then in increments of 3 rows, etc. Since striding does not work this way, it should work from a copy.
Note that y[0,0] modifies x[0,0] , but q[0] is independent of both.
While OWNDATA for q is false, it is True for y.ravel() and y.flatten() . I suspect that reshape() in this case makes a copy and then reformatts, and this is an intermediate copy that "owns" the data, q.base .