2

I know how to get a slice from a Numpy array using the C API this way:

    // 'arr' is a 2D Python array, already created
    PyObject pyArray = PyArray_FromAny(arr, PyArray_DescrFromType(NPY_FLOAT), 0, 0, NPY_ARRAY_DEFAULT, null);

    PyObject slice = PySlice_New(PyLong_FromLong(0), PyLong_FromLong(2), null);
    PyObject result = PyObject_GetItem(pyArray, slice);

This basically matches the following Python expression:

    arr[0:2]

Now, how can I get a "multi" slice from 'arr'? For instance, how can programmatically write the following expression?

    arr[0:2,0:3]
fred87100
  • 33
  • 2
  • I'm not sure and cannot test it, but can you try to create a tuple of slices and call GetItem passing the tuple? – Matteo Ragni Mar 13 '20 at 08:57
  • Slice creation works fine with two tuples (instead of two integers), with both tuples containing two integers. Calling PyObject_GetItem with these tuples results in the following error: TypeError: slice indices must be integers or None or have an __index__ method – fred87100 Mar 13 '20 at 09:18
  • Sorry but maybe I was not clear: create the two slices `PyObject slice_a = PySlice_New(PyLong_FromLong(0), PyLong_FromLong(2), null);` and `PyObject slice_b = PySlice_New(PyLong_FromLong(0), PyLong_FromLong(3), null);`, then create a tuple like `PyObject tuple = PyTuple_Pack(2, slice_a, slice_b)` and then call `PyObject result = PyObject_GetItem(pyArray, tuple);` – Matteo Ragni Mar 13 '20 at 09:27
  • My apology. I tried what you said, GetItem does succeed, but I get a crash when trying to print the result with: `PyDict_SetItemString(globals, "result", result); PyRun_SimpleStringFlags("print(result, flush=True)", null);` (printing code succeeds when my slice is 1D) – fred87100 Mar 13 '20 at 09:31
  • The rationale behind this is that the `__getitem__` in python(3) has signature `__getitem__(self, key)` and it is "not allowed" `__getitem__(self, key_1, key_2)`, thus in `array[0:2,0:3]` I suspect it is actually `array.__getitem__(self,key = (slice(0,2), slice(0,3)))` – Matteo Ragni Mar 13 '20 at 09:33
  • What is the return value of `PyDict_SetItemString`? – Matteo Ragni Mar 13 '20 at 09:35
  • Also I suspect that the result of `getitem` has been garbage collected when you try to print. – Matteo Ragni Mar 13 '20 at 09:37
  • Matteo, it works. The fact that the code was crashing was a side effect but the 1D-code that was still executed previously. Thanks a lot for your valuable help. Still learning Python, I understand a comma means nothing special except the argument is just a tuple! Thanks again. – fred87100 Mar 13 '20 at 09:40
  • Happy that we sorted that out, thank you for testing my suggestions. – Matteo Ragni Mar 13 '20 at 09:41
  • How can I mark your second post as answer? – fred87100 Mar 13 '20 at 09:42
  • I wrote an answer for that – Matteo Ragni Mar 13 '20 at 09:42

1 Answers1

2

In order to get multi dimensional slices you have to insert the slices in a tuple, the call the get item on that tuple. Something like:

PyObject* pyArray = PyArray_FromAny(arr, PyArray_DescrFromType(NPY_FLOAT), 0, 0, NPY_ARRAY_DEFAULT, null);

PyObject* slice_0 = PySlice_New(PyLong_FromLong(0), PyLong_FromLong(2), null);
PyObject* slice_1 = PySlice_New(PyLong_FromLong(0), PyLong_FromLong(3), null);
PyObject* slices = PyTuple_Pack(2, slice_0, slice_1);

PyObject* result = PyObject_GetItem(pyArray, slices);

The rationale behind it is the __getitem__(self, arg) (there is a single argument) thus multiple indexes are implicitly converted in a tuple: arg = (slice(0,2), slice(0,3),)

Robert Bain
  • 395
  • 1
  • 7
  • 19
Matteo Ragni
  • 2,837
  • 1
  • 20
  • 34