88 votes

Différence entre a - = b et a = a - b en Python

Récemment, j'ai appliqué cette solution pour en moyenne tous les N lignes de la matrice. Bien que la solution fonctionne en général j'ai eu des problèmes lorsqu'il est appliqué à un 7x1 tableau. J'ai remarqué que le problème est lors de l'utilisation de l' -=de l'opérateur. Pour faire un petit exemple:

import numpy as np

a = np.array([1,2,3])
b = np.copy(a)

a[1:] -= a[:-1]
b[1:] = b[1:] - b[:-1]

print a
print b

sorties:

[1 1 2]
[1 1 1]

Ainsi, dans le cas d'un tableau a -= b produit un résultat différent de celui a = a - b. Je pensais jusqu'à maintenant que ces deux moyens sont exactement les mêmes. Quelle est la différence?

Comment se fait la méthode que je suis en mentionnant pour additionnant tous les N lignes d'une matrice est de travail par exemple, pour un 7x4 de la matrice, mais pas pour une 7x1 tableau?

79voto

ajcr Points 4047

La mutation de tableaux lorsqu'ils sont utilisés dans les calculs peuvent conduire à des résultats inattendus!

Dans l'exemple de la question, la soustraction avec -= modifie le deuxième élément de l' a puis utilise immédiatement que modifiée deuxième élément de l'opération sur le troisième élément de la a.

Voici ce qui se passe avec a[1:] -= a[:-1] étape par étape:

  • a , est le tableau avec les données de l' [1, 2, 3].

  • Nous avons deux points de vue sur ces données: a[1:] est [2, 3], et a[:-1] est [1, 2].

  • La place de la soustraction -= commence. Le premier élément de a[:-1], 1, est soustrait du premier élément de a[1:]. Cela a modifié a être [1, 1, 3]. Maintenant, nous avons l' a[1:] est une vue de données [1, 3], et a[:-1] est une vue de données [1, 1] (le second élément du tableau a a été changé).

  • a[:-1] est désormais [1, 1] et NumPy doit maintenant soustraire sa deuxième élément , qui est de 1 (pas le 2!) à partir du deuxième élément de l' a[1:]. Cela rend a[1:] d'une vue sur les valeurs [1, 2].

  • a est maintenant un tableau avec les valeurs [1, 1, 2].

b[1:] = b[1:] - b[:-1] n'ont pas ce problème, car b[1:] - b[:-1] crée un nouveau tableau d'abord, puis affecte les valeurs dans ce tableau d' b[1:]. Elle ne modifie pas b , au cours de la soustraction, de sorte que le point de vue b[1:] et b[:-1] ne changent pas.


Le conseil général est d'éviter de modifier une vue directe avec l'autre, si elles se chevauchent. Cela inclut les opérateurs -=, *=, etc. et à l'aide de l' out paramètre dans les fonctions universelles (comme np.subtract et np.multiply) pour écrire de nouveau à l'un des tableaux.

43voto

glglgl Points 35668

En interne, la différence est que ceci:

a[1:] -= a[:-1]

est équivalent à ceci:

a[1:] = a[1:].__isub__(a[:-1])
a.__setitem__(slice(1, None, None), a.__getitem__(slice(1, None, None)).__isub__(a.__getitem__(slice(1, None, None)))

tandis que ceci:

b[1:] = b[1:] - b[:-1]

cartes à ceci:

b[1:] = b[1:].__sub__(b[:-1])
b.__setitem__(slice(1, None, None), b.__getitem__(slice(1, None, None)).__sub__(b.__getitem__(slice(1, None, None)))

Dans certains cas, __sub__() et __isub__() travaillent dans une manière similaire. Mais mutable objets de muter et de retourner eux-mêmes lors de l'utilisation d' __isub__(), alors qu'ils devraient renvoyer un nouvel objet avec __sub__().

L'application de la tranche des opérations sur numpy objets crée des points de vue sur eux, afin de les utiliser pour accéder directement à la mémoire de "l'original" de l'objet.

11voto

B. M. Points 5323

Les docs disent :

L'idée derrière augmentée d'affectation en Python, c'est qu'il n'est pas juste un moyen plus facile d'écrire le stockage de l' une opération binaire dans sa main gauche opérande, mais aussi un moyen pour la gauche de l'opérande en question, à savoir qu'il doit "sur lui-même", plutôt que de créer une copie modifiée de lui-même.

Comme un pouce règle, augmentée de soustraction (x-=y) x.__isub__(y), pour le ENplace de l'opération , SI possible, lors de la normale soustraction (x = x-y) x=x.__sub__(y) . Non mutable objets tels que les entiers, c'est l'équivalent. Mais pour mutable, comme des tableaux ou des listes, comme dans votre exemple, ils peuvent être des choses très différentes.

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