Si nous prenons b = [1,2,3]
et si nous essayons de faire:b+=(4,)
Il revient b = [1,2,3,4]
, mais si nous essayons de le faire, b = b + (4,)
cela ne fonctionne pas.
b = [1,2,3]
b+=(4,) # Prints out b = [1,2,3,4]
b = b + (4,) # Gives an error saying you can't add tuples and lists
Je m'attendais b+=(4,)
à l'échec car vous ne pouvez pas ajouter une liste et un tuple, mais cela a fonctionné. J'ai donc essayé de b = b + (4,)
m'attendre à obtenir le même résultat, mais cela n'a pas fonctionné.
python
python-3.x
list
tuples
Supun Dasantha Kuruppu
la source
la source
Réponses:
Le problème des questions «pourquoi» est qu’elles peuvent généralement signifier plusieurs choses différentes. Je vais essayer de répondre à chacune, je pense que vous pourriez avoir à l'esprit.
"Pourquoi est-il possible qu'il fonctionne différemment?" ce qui est répondu par exemple par ceci . Essentiellement,
+=
essaie d'utiliser différentes méthodes de l'objet:__iadd__
(qui n'est cochée que sur le côté gauche), vs__add__
et__radd__
("reverse add", cochée sur le côté droit si le côté gauche n'a pas__add__
) pour+
."Que fait exactement chaque version?" En bref, la
list.__iadd__
méthode fait la même chose quelist.extend
(mais à cause de la conception du langage, il y a toujours une affectation en arrière).Cela signifie également par exemple que
+
, bien sûr, crée un nouvel objet, mais requiert explicitement une autre liste au lieu d'essayer d'extraire des éléments d'une séquence différente."Pourquoi est-il utile pour + = de faire cela? C'est plus efficace; la
extend
méthode n'a pas à créer un nouvel objet. Bien sûr, cela a parfois des effets surprenants (comme ci-dessus), et généralement Python n'est pas vraiment une question d'efficacité , mais ces décisions ont été prises il y a longtemps."Quelle est la raison de ne pas autoriser l'ajout de listes et de tuples avec +?" Voir ici (merci, @ splash58); une idée est que (tuple + liste) devrait produire le même type que (liste + tuple), et il n'est pas clair de quel type le résultat devrait être.
+=
n'a pas ce problème, cara += b
il ne faut évidemment pas changer le type dea
.la source
|
, ce qui gâche un peu mon exemple. Si je pense à un exemple plus clair plus tard, je l'échangerai.|
pour les ensembles est un opérateur de navettage, mais pas+
pour les listes. Pour cette raison, je ne pense pas que l'argument concernant l'ambiguïté de type soit particulièrement fort. Puisque l'opérateur ne fait pas la navette pourquoi exiger la même chose pour les types? On pourrait simplement convenir que le résultat a le type de lhs. En revanche, en restreignantlist + iterator
, le développeur est encouragé à être plus explicite sur son intention. Si vous voulez créer une nouvelle liste qui contient la substance à partira
prolongée par les choses deb
il y a déjà une façon de le faire:new = a.copy(); new += b
. C'est une ligne de plus mais limpide.a += b
se comporte différemmenta = a + b
n'est pas l'efficacité. C'est en fait que Guido a jugé le comportement choisi moins déroutant. Imaginez une fonction recevant une listea
comme argument puis le faisanta += [1, 2, 3]
. Cette syntaxe semble certainement modifier la liste en place, plutôt que de créer une nouvelle liste, donc la décision a été prise qu'elle devrait se comporter selon l'intuition de la plupart des gens sur le résultat attendu. Cependant, le mécanisme devait également fonctionner pour des types immuables commeint
s, ce qui a conduit à la conception actuelle.a += b
un raccourcia = a + b
, comme l'a fait Ruby, mais je peux comprendre comment nous y sommes arrivés.Ils ne sont pas équivalents:
est un raccourci pour:
tout en
+
concatène les listes, donc en:vous essayez de concaténer un tuple dans une liste
la source
Lorsque vous faites cela:
est converti en ceci:
Sous le capot, il appelle
b.extend((4,))
,extend
accepte un itérateur et c'est pourquoi cela fonctionne également:mais quand vous faites cela:
est converti en ceci:
accepter uniquement l'objet de liste.
la source
À partir des documents officiels, pour les types de séquence mutables :
sont définis comme:
Ce qui est différent de celui défini comme:
Cela signifie également que tout type de séquence fonctionnera
t
, y compris un tuple comme dans votre exemple.Mais cela fonctionne aussi pour les gammes et les générateurs! Par exemple, vous pouvez également faire:
la source
Les opérateurs d'affectation "augmentés" comme
+=
ont été introduits dans Python 2.0, qui a été publié en octobre 2000. La conception et la justification sont décrites dans PEP 203 . L'un des objectifs déclarés de ces opérateurs était de soutenir les opérations sur place. L'écritureest censé mettre à jour la liste
a
en place . Cela est important s'il existe d'autres références à la listea
, par exemple quand aa
été reçu comme argument de fonction.Cependant, l'opération ne peut pas toujours se produire sur place, car de nombreux types Python, y compris les entiers et les chaînes, sont immuables , par exemple
i += 1
pour un entieri
ne peut pas fonctionner sur place.En résumé, les opérateurs d'affectation augmentée étaient censés fonctionner sur place lorsque cela était possible et créer un nouvel objet dans le cas contraire. Pour faciliter ces objectifs de conception, l'expression a
x += y
été spécifiée pour se comporter comme suit:x.__iadd__
est défini,x.__iadd__(y)
est évalué.x.__add__
est implémentéx.__add__(y)
est évalué.y.__radd__
est implémentéy.__radd__(x)
est évalué.Le premier résultat obtenu par ce processus sera affecté à nouveau
x
(sauf si ce résultat est leNotImplemented
singleton, auquel cas la recherche se poursuit à l'étape suivante).Ce processus permet aux types qui prennent en charge la modification sur place à implémenter
__iadd__()
. Les types qui ne prennent pas en charge la modification sur place n'ont pas besoin d'ajouter de nouvelles méthodes magiques, car Python reviendra automatiquement à essentiellementx = x + y
.Venons-en enfin à votre question réelle - pourquoi vous pouvez ajouter un tuple à une liste avec un opérateur d'affectation augmenté. De mémoire, l'historique de ceci était à peu près comme ceci: La
list.__iadd__()
méthode a été implémentée pour appeler simplement lalist.extend()
méthode déjà existante dans Python 2.0. Lorsque les itérateurs ont été introduits dans Python 2.1, lalist.extend()
méthode a été mise à jour pour accepter les itérateurs arbitraires. Le résultat final de ces changements amy_list += my_tuple
fonctionné à partir de Python 2.1. Lalist.__add__()
méthode, cependant, n'a jamais été censé soutenir itérateurs arbitraires comme argument de droite - cela a été jugé inapproprié pour un langage fortement typé.Personnellement, je pense que l'implémentation des opérateurs augmentés a fini par être un peu trop complexe en Python. Il a de nombreux effets secondaires surprenants, par exemple ce code:
La deuxième ligne soulève
TypeError: 'tuple' object does not support item assignment
, mais l'opération est réalisée avec succès de toute façon -t
sera([42, 44], [43])
après l' exécution de la ligne qui soulève l'erreur.la source
La plupart des gens s'attendraient à ce que X + = Y soit équivalent à X = X + Y. En effet, la référence de poche Python (4e éd.) De Mark Lutz dit à la page 57 "Les deux formats suivants sont à peu près équivalents: X = X + Y, X + = Y ". Cependant, les personnes qui ont spécifié Python ne les ont pas rendues équivalentes. Peut-être que c'était une erreur qui entraînera des heures de temps de débogage par des programmeurs frustrés aussi longtemps que Python restera utilisé, mais c'est maintenant exactement comme Python. Si X est un type de séquence mutable, X + = Y est équivalent à X.extend (Y) et non à X = X + Y.
la source
Comme il est expliqué ici , si
array
n'implémente pas la__iadd__
méthode, leb+=(4,)
serait juste un raccourcib = b + (4,)
mais ce n'est évidemment pas le cas, il enarray
va de même pour la__iadd__
méthode. Apparemment, l'implémentation de la__iadd__
méthode ressemble à ceci:Cependant, nous savons que le code ci-dessus n'est pas l'implémentation réelle de la
__iadd__
méthode, mais nous pouvons supposer et accepter qu'il existe quelque chose comme laextend
méthode, qui accepte lestupple
entrées.la source