<div dir="ltr">I agree with Stefan that option 2 is what NumPy should go with for .copy()<div><br></div><div>If you want to get an identical memory copy you should be getting the .data attribute and doing something with that buffer. </div><div><br></div><div>My $0.02</div><div><br></div><div>-Travis</div><div><br></div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Thu, Apr 11, 2019 at 6:01 PM Stefan van der Walt <<a href="mailto:stefanv@berkeley.edu">stefanv@berkeley.edu</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">Hi Marten,<br>
<br>
On Thu, 11 Apr 2019 09:51:10 -0400, Marten van Kerkwijk wrote:<br>
> From the discussion so far, it<br>
> seems the logic has boiled down to a choice between:<br>
> <br>
> (1) Copy is a contract that the dtype will not vary (e.g., we also do not<br>
> change endianness);<br>
> <br>
> (2) Copy is a contract that any access to the data in the array will return<br>
> exactly the same result, without wasting memory and possibly optimized for<br>
> access with different strides. E.g., `array[::10].copy() also compacts the<br>
> result.<br>
<br>
I think you'll get different answers, depending on whom you ask—those<br>
interested in low-level memory layout, vs those who use the higher-level<br>
API.  Given that higher-level API use is much more common, I would lean<br>
in the direction of option (2).<br>
<br>
>From that perspective, we already don't make consistency guarantees about memory<br>
layout and other flags.  E.g.,<br>
<br>
In [16]: x = np.arange(12).reshape((3, 4))                                                                                                                                           <br>
In [17]: x.strides                                                                                                                                                                  <br>
Out[17]: (32, 8)<br>
<br>
In [18]: x[::2, 1::2].strides                                                                                                                                                       Out[18]: (64, 16)<br>
<br>
In [19]: np.copy(x[::2, 1::2]).strides                                                                                                                                              <br>
Out[19]: (16, 8)<br>
<br>
Not to mention this odd copy contract:<br>
<br>
>>> x = np.array([[1,2,3],[4,5,6]], order='F')<br>
>>> print(np.copy(x).flags['C_CONTIGUOUS'])<br>
>>> print(x.copy().flags['C_CONTIGUOUS'])<br>
<br>
False<br>
True<br>
<br>
<br>
The objection about arrays that don't behave identically in [0] feels<br>
somewhat arbitary to me.  As shown above, you can always find attributes<br>
that differ between a copied array and the original.<br>
<br>
The user's expectation is that they'll get an array that behaves the<br>
same way as the original, not one that is byte-for-byte compatible.  The<br>
most common use case is to make sure that the original array doesn't get<br>
overwritten.<br>
<br>
Just to play devil's advocate with myself: if you do choose option (2),<br>
how would you go about making an identical memory copy of the original array?<br>
<br>
Best regards,<br>
Stéfan<br>
<br>
<br>
[0] <a href="https://github.com/numpy/numpy/issues/13299#issuecomment-481912827" rel="noreferrer" target="_blank">https://github.com/numpy/numpy/issues/13299#issuecomment-481912827</a><br>
_______________________________________________<br>
NumPy-Discussion mailing list<br>
<a href="mailto:NumPy-Discussion@python.org" target="_blank">NumPy-Discussion@python.org</a><br>
<a href="https://mail.python.org/mailman/listinfo/numpy-discussion" rel="noreferrer" target="_blank">https://mail.python.org/mailman/listinfo/numpy-discussion</a><br>
</blockquote></div>