Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Attempt to grow array by assigning a size-1 array to a size-0 slice doesn't throw exception #11309

Open
o11c opened this issue Jun 11, 2018 · 6 comments

Comments

@o11c
Copy link

o11c commented Jun 11, 2018

Per documentation:

You may use slicing to set values in the array, but (unlike lists) you can never grow the array. The size of the value to be set in x[obj] = value must be (broadcastable) to the same shape as x[obj].

(aside: the documentation could mention "never grow (or shrink)")

However, instead of throwing an exception, the following code silently does nothing.

In [1]: import numpy as np

In [2]: a = np.arange(10)

In [3]: a[5:5] = [123]

In [4]: a
Out[4]: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

Other cases correctly throw the exception:

In [10]: a[5:5] = [123, 456]
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-10-d4b9d8302fa7> in <module>()
----> 1 a[5:5] = [123, 456]

ValueError: cannot copy sequence with size 2 to array axis with dimension 0

In [11]: a[5:6] = [123, 456]
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-11-ed78eec154a9> in <module>()
----> 1 a[5:6] = [123, 456]

ValueError: cannot copy sequence with size 2 to array axis with dimension 1

In [12]: a[5:6] = []
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-12-4e280c717263> in <module>()
----> 1 a[5:6] = []

ValueError: cannot copy sequence with size 0 to array axis with dimension 1

In [13]: a
Out[13]: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

Discovered with numpy 1.12.1 from Debian, but verified with numpy 1.14.4 from PyPI.

@mhvk
Copy link
Contributor

mhvk commented Jun 11, 2018

Thanks for reporting. Seems like a bug to me.

@eric-wieser
Copy link
Member

This is broadcasting, and works for the same reason as:

x[:10] = [1]
x[:1] = [1]
x[:0] = [1]

@seberg
Copy link
Member

seberg commented Jun 11, 2018

Well, it may seem a bit strange, but correct by broadcasting rules, since 1 can be broadcast to 0. In fact, it suddenly all makes sense if you think about it:

arr1d[:] = 5

and then decide arr1d can have any size including length zero. In all cases all elements are set to 5.

@mhvk
Copy link
Contributor

mhvk commented Jun 11, 2018

Well, it is clear I can still get caught out by broadcasting! I removed the "bug" label. @o11c - you clearly consulted the docs and were confused, which suggests a need for clarity; would you have a suggestion for how to write it differently? Maybe giving your example, or @seberg's, would help?

@o11c
Copy link
Author

o11c commented Jun 12, 2018

I suppose the documentation I cited needs to add a link, and the broadcasting page needs to mention that it considers assignment an operation, but documentation sucks as a resource anyway ... modifying the exception message would be far more help (though the fact that the exception even can be different smells of copypasta).

Honestly, I'm more confused now than before, w.r.t. broadcasting. I've only ever used it with a different number of axes (e.g. np.arange(10) * 3); I never imagined that np.arange(10) * [3] would count as broadcasting (although at least that case gives a helpful error message for higher sizes ... which is exactly the opposite of what I would expect since np.arange(10) * [3] implies np.arange(10) * [3, 4] should work).

If I ever had wanted to do something like that, I would (and probably did, sometime) call np.ndarray(..., strides=(0,)) which already works without needing any special logic, and is thus far more intuitive.

As it is, the sloppiness feels purely like a design bug that's too late to change. Did somebody say something like "There should be 3, and preferably more than 3, counterintuitive ways to do it"?

@seberg
Copy link
Member

seberg commented Jun 12, 2018

Frankly, there is one way, and it is broadcasting whether you like it the implicit zero stride allowed for 1 sized dimensions or not. Or since we are citing, another way to put it:

There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.

So, unless you are dutch, lets agree it is in the eye of the beholder. Building a 0 strided array is definitely not the intended (or obvious) way in most cases, and using np.ndarray to do it is even odder.

Obviously you are right, we are stuck with it, but I think broadcasting is one of those thing generally considered a big step in the right direction. The docs (and error messages) can always use improvements, although I am not sure where the inconsistency in the error messages is exactly. (I am sure it is there, there are plenty of really very different things that look similar, and some of those would be nice to consolidate. Those are things that generally happen, albeit slowly, unless someone steps up and does it).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants