Подтвердить что ты не робот

Что означает "три точки" в Python при индексировании того, что выглядит как число?

Что означает x[...] ниже?

a = np.arange(6).reshape(2,3)
for x in np.nditer(a, op_flags=['readwrite']):
    x[...] = 2 * x
4b9b3361

Ответ 1

В то время как предложенный дубликат Что делает объект Python Ellipsis? отвечает на вопрос в общем контексте python, его использование в цикле nditer требует, я думаю, дополнительной информации.

https://docs.scipy.org/doc/numpy/reference/arrays.nditer.html#modifying-array-values

Регулярное присваивание в Python просто изменяет ссылку в словаре локальной или глобальной переменной вместо изменения существующей переменной на месте. Это означает, что простое присвоение x не поместит значение в элемент массива, а переключит x с ссылки на элемент массива на ссылку на назначенное вами значение. Чтобы действительно изменить элемент массива, x должен быть проиндексирован с помощью многоточия.

Этот раздел включает в себя ваш пример кода.

Так что, по моим словам, x[...] =... изменяет x на месте; x =... сломал бы ссылку на переменную nditer и не изменил бы ее. Это похоже на x[:] =... но работает с массивами любого измерения (включая 0d). В этом контексте x не просто число, это массив.

Пожалуй, ближе всего к этой nditer итерации, без nditer является:

In [667]: for i, x in np.ndenumerate(a):
     ...:     print(i, x)
     ...:     a[i] = 2 * x
     ...:     
(0, 0) 0
(0, 1) 1
...
(1, 2) 5
In [668]: a
Out[668]: 
array([[ 0,  2,  4],
       [ 6,  8, 10]])

Обратите внимание, что я должен был индексировать и изменять a[i] напрямую. Я не мог бы использовать, x = 2*x. В этой итерации x является скаляром и, следовательно, не является изменяемым

In [669]: for i,x in np.ndenumerate(a):
     ...:     x[...] = 2 * x
  ...
TypeError: 'numpy.int32' object does not support item assignment

Но в случае nditer x является массивом 0d и является изменяемым.

In [671]: for x in np.nditer(a, op_flags=['readwrite']):
     ...:     print(x, type(x), x.shape)
     ...:     x[...] = 2 * x
     ...:     
0 <class 'numpy.ndarray'> ()
4 <class 'numpy.ndarray'> ()
...

И так как это 0d, x[:] не может использоваться вместо x[...]

----> 3     x[:] = 2 * x
IndexError: too many indices for array

Более простая итерация массива также может дать понимание:

In [675]: for x in a:
     ...:     print(x, x.shape)
     ...:     x[:] = 2 * x
     ...:     
[ 0  8 16] (3,)
[24 32 40] (3,)

это перебирает строки (1-й тусклый) a. x тогда является 1d массивом и может быть изменен с помощью x[:]=... или x[...]=...

И если я добавлю флаг external_loop из следующего раздела, x теперь будет 1d массивом, и x[:] = будет работать. Но x[...] = все еще работает и носит более общий характер. x[...] используются все другие nditer примеров.

In [677]: for x in np.nditer(a, op_flags=['readwrite'], flags=['external_loop']):
     ...:     print(x, type(x), x.shape)
     ...:     x[...] = 2 * x
[ 0 16 32 48 64 80] <class 'numpy.ndarray'> (6,)

Сравните эту простую итерацию строки (на 2d массиве):

In [675]: for x in a:
     ...:     print(x, x.shape)
     ...:     x[:] = 2 * x
     ...:     
[ 0  8 16] (3,)
[24 32 40] (3,)

это перебирает строки (1-й тусклый) a. x тогда является 1d массивом и может быть изменен с помощью x[:] =... или x[...] =...

Читайте и экспериментировать с этой nditer страницы весь путь до конца. Сам по себе nditer не так полезен в python. Это не ускоряет итерацию - пока вы не cython свой код на cython. np.ndindex - одна из немногих не скомпилированных функций numpy которая использует nditer.