-
-
Notifications
You must be signed in to change notification settings - Fork 12.2k
Description
A very painful bug of mine turns out to originate in the different behaviors of np.copy(a) and a.copy() — specifically, the fact that the latter preserves subclass, whereas the former does not.
If I look through the actual code, it's clear why this happens, but it's certainly not clear from the documentation that it will happen. In fact, I consider the documentation for np.copy downright misleading because it addresses one difference between the two (namely, the default order argument), which lulled me into believing that it was the only difference. (And yes, the documentation technically refers to ndarray.copy, while my subclass was not ndarray, but I don't read documentation like a lawyer.)
I'll acknowledge that changing the default behavior is off the table, so I'll suggest two possibilities that would at least help avoid this situation:
-
Add a
subok=Falseoption tonp.copythat is just passed through tonp.array. The default behavior will remain the same, but the presence of this argument will alert the user to the fact that there might be an issue. -
Add to the docstring an explicit statement of the fact that subclasses will not pass through.
numpy/numpy/lib/function_base.py
Lines 745 to 790 in d9b1e32
| @array_function_dispatch(_copy_dispatcher) | |
| def copy(a, order='K'): | |
| """ | |
| Return an array copy of the given object. | |
| Parameters | |
| ---------- | |
| a : array_like | |
| Input data. | |
| order : {'C', 'F', 'A', 'K'}, optional | |
| Controls the memory layout of the copy. 'C' means C-order, | |
| 'F' means F-order, 'A' means 'F' if `a` is Fortran contiguous, | |
| 'C' otherwise. 'K' means match the layout of `a` as closely | |
| as possible. (Note that this function and :meth:`ndarray.copy` are very | |
| similar, but have different default values for their order= | |
| arguments.) | |
| Returns | |
| ------- | |
| arr : ndarray | |
| Array interpretation of `a`. | |
| Notes | |
| ----- | |
| This is equivalent to: | |
| >>> np.array(a, copy=True) #doctest: +SKIP | |
| Examples | |
| -------- | |
| Create an array x, with a reference y and a copy z: | |
| >>> x = np.array([1, 2, 3]) | |
| >>> y = x | |
| >>> z = np.copy(x) | |
| Note that, when we modify x, y changes, but not z: | |
| >>> x[0] = 10 | |
| >>> x[0] == y[0] | |
| True | |
| >>> x[0] == z[0] | |
| False | |
| """ | |
| return array(a, order=order, copy=True) |