2010-12-07 57 views
14

je suis tombé sur quelque chose d'intéressant au sujet de l'affectation augmentée python +=Python problème d'affectation augmenté

il semble être la conversion automatique de type de données ne sont pas toujours fait pour a += b si un est un type de données « plus simple », alors que a = a + b semble Travaillez toujours

cas où la conversion se fait

a = 1 
b = 1j 

a = 1 
b = 0.5 

cas où la conversion ne se fait pas

from numpy import array 
a = array([0, 0 ,0]) 
b = array([0, 0, 1j]) 

après a += b, a reste comme matrice entière, au lieu de la matrice complexe

Je pensais que a += b est le même que a = a + b, quelle est la différence d'entre eux dans la mise en œuvre sous-jacente?

+0

À quoi fait référence 'array' dans votre exemple? Est-ce à partir du module builtin 'array'? Si oui, votre exemple ne fonctionne même pas, car il n'y a pas de code de type ... – SingleNegationElimination

+0

'a = array ([0, 0, 0])' et 'b = array ([0, 0, 1j])' don ' t travailler avec la classe 'array' dans le module du même nom. Ils manquent tous les deux un argument * typecode * initial. Et, AFAIK, la classe ne supporte pas les nombres complexes ni l'assignation augmentée "+ =". Donc je ne comprends pas ce que vous demandez ici. – martineau

+0

@martineau Voir mon commentaire sur la réponse de Rafe (maintenant supprimé.) En référence à cette question numérique: http://www.scipy.org/FAQ#head-1ed851e9aff803d41d3cded8657b2b15a888ebd5 – ACoolie

Répondre

15

Pour l'opérateur +, Python définit trois méthodes "spéciales" qu'un objet peut mettre en œuvre:

  • __add__: ajoute deux éléments (+ opérateur). Lorsque vous faites a + b, la méthode __add__ de a est appelée avec b en tant qu'argument.
  • __radd__: addition réfléchie; Pour a + b, la méthode __radd__ de b est appelée avec a comme instance. Ceci est seulement utilisé quand a ne sait pas comment faire l'addition et les deux objets sont de types différents.
  • __iadd__: ajout sur place; utilisé pour a += b où le résultat est attribué à la variable de gauche. Ceci est fourni séparément car il pourrait être possible de l'implémenter de manière plus efficace. Par exemple, si a est une liste, alors a += b est identique à a.extend(b). Cependant, dans le cas de c = a + b vous devez faire une copie de a avant de l'étendre puisque a ne doit pas être modifié dans ce cas. Notez que si vous n'implémentez pas __iadd__, Python appellera simplement __add__ à la place.

Donc, puisque ces différentes opérations sont mises en œuvre avec des méthodes distinctes, il est possible (mais généralement une mauvaise pratique) pour les mettre en œuvre afin qu'ils font des choses tout à fait différentes, ou peut-être dans ce cas, seulement légèrement choses différentes.

D'autres ont déduit que vous utilisez NumPy et expliqué son comportement. Cependant, vous avez posé des questions sur l'implémentation sous-jacente. Espérons que vous voyez maintenant pourquoi il est parfois le cas que a += b n'est pas le même que a = a + b. En passant, un trio similaire de méthodes peut également être mis en œuvre pour d'autres opérations. Voir this page pour une liste de toutes les méthodes en place prises en charge.

+1

Je dois noter que dans l'exemple que j'ai donné pour les listes, 'a + = b' a en fait des résultats différents de' a = a + b'. Si 'a' est connu sous un autre nom, cet autre nom" verra "la liste étendue après' a + = b' mais pas après 'a = a + b'. – kindall

0

La réponse de Rafe Kettler est correcte, mais il semble que vous ayez réussi à obtenir a = [0,0,0] après l'avoir ajouté à b (selon votre message).

Eh bien, si vous utilisez numpy ou scipy (Je dis cela parce que je vois array et me demande ce tableau est en cours de création), alors ceci est « normal », et devrait même soulever un avertissement:

ComplexWarning: Moulage valeurs complexes pour les rejets réels de la partie imaginaire

1

la différence entre a = a + b et a += b est, que celle-ci sera plus, chaque fois que possible, faire « in-situ », cela signifie en changeant l'objet a. Vous pouvez facilement voir cela avec des listes.

a = b = [1, 2] 
a += [3] 
print b # [1, 2, 3] 
a = b = [1, 2] 
a = a + [3] 
print b # [1, 2] 
+0

Oui, et dans le cas des tableaux numpy, cela veut dire garder le même type de 'a', donc les nombres complexes ne seront pas représentés. – tkerwin

7

Si array est numpy.array (vous ne spécifiez pas réellement), la question qui se passe est parce que ces tableaux ne peuvent pas changer leur type. Lorsque vous créez le tableau sans spécificateur de type, il devine un type. Si vous essayez ensuite de faire une opération que ce type ne supporte pas (comme l'ajouter à un type avec un domaine plus grand, comme complexe), numpy sait effectuer le calcul, mais il sait aussi que le résultat ne peut être stocké que dans le type avec le plus grand domaine. Il se plaint (sur ma machine, de toute façon, la première fois que je fais une telle affectation) que le résultat ne correspond pas. Quand vous faites un ajout régulier, un nouveau tableau doit être fait dans tous les cas, et numpy lui donne le bon type.

>>> a=numpy.array([1]) 
>>> a.dtype 
dtype('int32') 
>>> b=numpy.array([1+1j]) 
>>> b.dtype 
dtype('complex128') 
>>> a+b 
array([ 2.+1.j]) 
>>> (a+b).dtype 
dtype('complex128') 
>>> a+=b 
>>> a 
array([2]) 
>>> a.dtype 
dtype('int32') 
>>>