Personally I was a fan of the Enum approach. People dislike it because it is not “Pythonic”, but imho that is an accident of history because Enums only appeared (iirc) in Python 3.4. In fact, they are the right data structure for this particular problem, so for my money we should *make it* Pythonic by starting to use it everywhere where we have a finite list of choices.

Juan.

On 24 Jun 2021, at 4:09 am, Stefan van der Walt stefanv@berkeley.edu wrote:

Perhaps it is also worth going back to explore our original motivation for making this change.

One reason was that Sebastian didn't like people doing `x.shape = ...`. Users do that, presumably, to trigger an error if a copy needs to be made. However, we can catch that already:

x = np.reshape(y, ...) if np.may_share_memory(x, y): ...

We can fix Sebastian's issue by introducing a `copy` keyword to `reshape`, which currently has none:

x = np.reshape(y, copy='never')

For consistency, it would be nice to have `np.array` support copy=never, but if there is no urgency we can take the long route towards an API that uses strings (consistent with the rest of NumPy).

The arguments against string names *right now* is that, if users write code with `copy='if-needed'` it will not work correctly with old NumPy code, since old versions will evaluate `if-needed` to True. The assessment was that this happens frequently, but we should consider how frequently, and how big of an issue it is.

So, I guess ultimately I am wondering if the change to `np.array` is needed right now, or whether we can get away without it for a while.

Stéfan

On Tue, Jun 22, 2021, at 15:21, bas van beek wrote:

Stefan, that sketch is more complicated than it needs to be - `np.copy` is a python function, so you can just attach the attributes directly! (although maybe there are implications for static typing)

For the type annotations we can simply use something akin to Stéfans proposed `NpCopy` class; probably in combination with `Protocol`. It's a bit more work compared to annotating a normal python function, but it's quite easy nevertheless.

Regards, Bas

*From:* NumPy-Discussion numpy-discussion-bounces+bas.vanbeek=hotmail.com@python.org on behalf of Eric Wieser wieser.eric+numpy@gmail.com *Sent:* 21 June 2021 18:56 *To:* Discussion of Numerical Python numpy-discussion@python.org *Subject:* Re: [Numpy-discussion] copy="never" discussion and no deprecation cycle?

Stefan, that sketch is more complicated than it needs to be - `np.copy` is a python function, so you can just attach the attributes directly! (although maybe there are implications for static typing)

`class CopyFlag(enum.Enum): IF_NEEDED = 0 ALWAYS = 1 NEVER = 2 np.copy.IF_NEEDED = CopyFlag.IF_NEEDED np.copy.ALWAYS = CopyFlag.ALWAYS np.copy.NEVER = CopyFlag.NEVER`

It would also work nicely for the `True/False/other` version that was proposed in the much older PR as `np.never_copy`:

`class _CopyNever: def __bool__(self): raise ValueError np.copy.NEVER = _CopyNever()`

All of these versions (and using the enum directly) seem fine to me. If we go down the enum route route, we probably want to add "new-style" versions of `np.CLIP` and friends that are true enums / live within a more obvious namespace.

Eric

On Mon, 21 Jun 2021 at 17:24, Stefan van der Walt stefanv@berkeley.edu wrote:

On Sun, Jun 20, 2021, at 20:46, Gagandeep Singh wrote:

I have recently joined the mailing list and have gone through the previous discussions on this thread. I would like to share my analysis (advantages and disadvantages) of three possible alternatives (Enum, String, boolean) to support the proposed feature.

Thanks for this thorough analysis, Gagandeep!

I'll throw one more heretical idea out there:

`np.copy.IF_NEEDED`, `np.copy.ALWAYS`, `np.copy.NEVER`.

This has the advantages of the enum, doesn't pollute the global namespace, and has an intuitive name.

`np.array(x, copy=np.copy.ALWAYS)`

It would be slightly more awkward to type, but is doable. A rough Python version sketch would be:

class CopyFlag(enum.Enum): IF_NEEDED = 0 ALWAYS = 1 NEVER = 2

class NpCopy: IF_NEEDED : CopyFlag = CopyFlag.IF_NEEDED ALWAYS : CopyFlag = CopyFlag.ALWAYS NEVER : CopyFlag = CopyFlag.NEVER

def __call__(self, x): return ...whatever copy returns...

np.copy = NpCopy()

Stéfan _______________________________________________ NumPy-Discussion mailing list NumPy-Discussion@python.org https://mail.python.org/mailman/listinfo/numpy-discussion

NumPy-Discussion mailing list NumPy-Discussion@python.org https://mail.python.org/mailman/listinfo/numpy-discussion

NumPy-Discussion mailing list NumPy-Discussion@python.org https://mail.python.org/mailman/listinfo/numpy-discussion