133 votes

Que signifie "trois points" en Python lors de l'indexation de ce qui ressemble à un nombre ?

Quelle est la signification de x[...] ci-dessous ?

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

1 votes

Ce n'est pas une liste.

2 votes

Duplicata possible de Que fait l'objet Python Ellipsis ?

1 votes

La conférence de James Powell est une façon amusante de comprendre cela. youtube.com/watch?v=65_-6kEAq58

90voto

hpaulj Points 6132

Alors que le duplicata proposé Que fait l'objet Python Ellipsis ? répond à la question de manière générale python contexte, son utilisation dans un nditer boucle nécessite, je pense, des informations supplémentaires.

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

L'affectation régulière en Python change simplement une référence dans le dictionnaire des variables locales ou globales au lieu de modifier une variable existante sur place. Cela signifie que la simple affectation à x ne placera pas la valeur dans l'élément du tableau, mais fera plutôt passer x d'une référence à un élément du tableau à une référence à la valeur que vous avez affectée. Pour modifier réellement l'élément du tableau, x doit être indexé avec le point de suspension.

Cette section comprend votre exemple de code.

Donc, selon mes mots, le x[...] = ... modifie x en place ; x = ... aurait rompu le lien avec le nditer et ne l'a pas modifiée. C'est comme si x[:] = ... mais fonctionne avec des tableaux de toute dimension (y compris 0d). Dans ce contexte x n'est pas seulement un nombre, c'est un tableau.

Peut-être que la chose la plus proche de cette nditer itération, sans nditer est :

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

Remarquez que j'ai dû indexer et modifier a[i] directement. Je n'aurais pas pu l'utiliser, x = 2*x . Dans cette itération x est un scalaire, et donc non mutable

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

Mais dans le nditer cas x est un tableau 0d, et 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'> ()
...

Et parce que c'est 0d, x[:] ne peut pas être utilisé à la place de x[...]

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

Une itération de tableau plus simple pourrait également donner un aperçu :

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

ceci itère sur les rangées (1ère dim) de a . x est alors un tableau 1d, et peut être modifié avec soit x[:]=... ou x[...]=... .

Et si j'ajoute le external_loop du prochain section , x est maintenant un tableau 1d, et x[:] = fonctionnerait. Mais x[...] = fonctionne toujours et est plus général. x[...] est utilisé tous les autres nditer exemples.

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

Comparez cette simple itération en ligne (sur un tableau 2d) :

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

ceci itère sur les rangées (1ère dim) de a . x est alors un tableau 1d, et peut être modifié avec soit x[:] = ... ou x[...] = ... .

Lisez et expérimentez avec ceci nditer page jusqu'à la fin. Par lui-même, nditer n'est pas très utile dans python . Il n'accélère pas l'itération - pas jusqu'à ce que vous portiez votre code vers cython . np.ndindex est l'un des rares programmes non compilés numpy qui utilise nditer .

0 votes

Notez que des choses comme x[1, :,...] sont également une syntaxe autorisée. Laissé pour référence future.

21voto

Aaron Points 2993

L'ellipse ... signifie as many : as needed .

Pour les personnes qui n'ont pas le temps, voici un exemple simple :

In [64]: X = np.reshape(np.arange(9), (3,3))

In [67]: Y = np.reshape(np.arange(2*3*4), (2,3,4))

In [70]: X
Out[70]:
array([[0, 1, 2],
       [3, 4, 5],
       [6, 7, 8]])

In [71]: X[:,0]
Out[71]: array([0, 3, 6])

In [72]: X[...,0]
Out[72]: array([0, 3, 6])

In [73]: Y
Out[73]:
array([[[ 0,  1,  2,  3],
        [ 4,  5,  6,  7],
        [ 8,  9, 10, 11]],

       [[12, 13, 14, 15],
        [16, 17, 18, 19],
        [20, 21, 22, 23]]])

In [74]: Y[:,0]
Out[74]:
array([[ 0,  1,  2,  3],
       [12, 13, 14, 15]])

In [75]: Y[...,0]
Out[75]:
array([[ 0,  4,  8],
       [12, 16, 20]])

In [76]: X[0,...,0]
Out[76]: array(0)

In [77]: Y[0,...,0]
Out[77]: array([0, 4, 8])

Cela permet de manipuler facilement une seule dimension à la fois.

Une chose - Vous ne pouvez avoir qu'une seule ellipse dans une expression d'indexation donnée, ou votre expression serait ambiguë quant au nombre d'ellipses. : devrait être mis dans chacun.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X