¿Qué significa "tres puntos" en Python al indexar lo que parece un número?

Respuestas:

69

Mientras que el duplicado propuesto ¿Qué hace el objeto Python Ellipsis? responde a la pregunta en un pythoncontexto general , su uso en un nditerbucle requiere, creo, información adicional.

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

La asignación regular en Python simplemente cambia una referencia en el diccionario de variable local o global en lugar de modificar una variable existente en su lugar. Esto significa que simplemente asignar ax no colocará el valor en el elemento de la matriz, sino que cambiará x de ser una referencia de elemento de matriz a ser una referencia al valor que asignó. Para modificar realmente el elemento de la matriz, x debe indexarse ​​con puntos suspensivos.

Esa sección incluye su ejemplo de código.

Entonces, en mis palabras, las x[...] = ...modificaciones xen el lugar; x = ...habría roto el enlace a la nditervariable y no lo habría cambiado. Es como, x[:] = ...pero funciona con matrices de cualquier dimensión (incluido 0d). En este contexto, xno es solo un número, es una matriz.

Quizás lo más cercano a esta nditeriteración, sin nditeres:

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]])

Observe que tuve que indexar y modificar a[i]directamente. No podría haber usado x = 2*x,. En esta iteración xes un escalar y, por lo tanto, no es mutable

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

Pero en el nditercaso xes una matriz 0d y mutable.

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'> ()
...

Y debido a que es 0d, x[:]no se puede usar en lugar dex[...]

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

Una iteración de matriz más simple también podría brindar información:

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

esto itera en las filas (primera atenuación) de a. xes entonces una matriz 1d y se puede modificar con x[:]=...o x[...]=....

Y si agrego la external_loopbandera de la siguiente sección , xahora es una matriz 1d y x[:] =funcionaría. Pero x[...] =todavía funciona y es más general. x[...]se utiliza todos los demás nditerejemplos.

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,)

Compare esta iteración de fila simple (en una matriz 2d):

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

esto itera en las filas (primera atenuación) de a. xes entonces una matriz 1d y se puede modificar con x[:] = ...o x[...] = ....

Lea y experimente con esta nditerpágina hasta el final. Por sí solo, nditerno es tan útil en python. No acelera la iteración, no hasta que transfiera su código a cython. np.ndindexes una de las pocas numpyfunciones no compiladas que utiliza nditer.

hpaulj
fuente
Tenga en cuenta que cosas como x [1,:, ...] también son una sintaxis permitida. Dejado para referencia futura.
borgr