[Numpy-discussion] ndrange, like range but multidimensiontal

Allan Haldane allanhaldane at gmail.com
Mon Oct 8 15:33:18 EDT 2018


On 10/8/18 12:21 PM, Mark Harfouche wrote:
> 2. `ndindex` is an iterator itself. As proposed, `ndrange`, like
> `range`, is not an iterator. Changing this behaviour would likely lead
> to breaking code that uses that assumption. For example anybody using
> introspection or code like:
> 
> ```
> indx = np.ndindex(5, 5)
> next(indx)  # Don't look at the (0, 0) coordinate
> for i in indx:
>     print(i)
> ```
> would break if `ndindex` becomes "not an iterator"

OK, I see now. Just like python3 has separate range and range_iterator
types, where range is sliceable, we would have separate ndrange and
ndindex types, where ndrange is sliceable. You're just copying the
python3 api. That justifies it pretty well for me.

I still think we shouldn't have two functions which do nearly the same
thing. We should only have one, and get rid of the other. I see two ways
forward:

 * replace ndindex by your ndrange code, so it is no longer an iter.
   This would require some deprecation cycles for the cases that break.
 * deprecate ndindex in favor of a new function ndrange. We would keep
   ndindex around for back-compatibility, with a dep warning to use
   ndrange instead.

Doing a code search on github, I can see that a lot of people's code
would break if ndindex no longer was an iter. I also like the name
ndrange for its allusion to python3's range behavior. That makes me lean
towards the second option of a separate ndrange, with possible
deprecation of ndindex.

> itertools.product + range seems to be much faster than the current
> implementation of ndindex
> 
> (python 3.6)
> ```
> %%timeit
> 
> for i in np.ndindex(100, 100):
>     pass
> 3.94 ms ± 19.4 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
> 
> %%timeit
> import itertools
> for i in itertools.product(range(100), range(100)):
>     pass
> 231 µs ± 1.09 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
> ```

If the new code ends up faster than the old code, that's great, and
further justification for using ndrange instead of ndindex. I had
thought using nditer in the old code was fastest.

So as far as I am concerned, I say go ahead with the PR the way you are
doing it.

Allan


More information about the NumPy-Discussion mailing list