Що означає "три крапки" на Python під час індексації того, що виглядає як число?


87

Що означає x[...]нижче?

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

1


1
Потрібно отримати цікавий спосіб зрозуміти це - виступ Джеймса Пауелла youtube.com/watch?v=65_-6kEAq58
SARose

Відповіді:


69

Поки пропонований дублікат Що робить об’єкт Python Ellipsis? відповідає на питання у загальному pythonконтексті, його використання в nditerциклі вимагає, я думаю, додаткової інформації.

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

Регулярне призначення в Python просто змінює посилання в локальному або глобальному словнику змінних замість того, щоб змінювати наявну змінну на місці. Це означає, що просто присвоєння 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. np.ndindexє однією з небагатьох некомпільованих numpyфункцій, яка використовує nditer.


Зауважте, що такі речі, як x [1,:, ...], також є дозволеним синтаксисом. Залишається для подальшого використання.
боргр
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.