Je ne sais pas comment on les appelle, mais je les vois tout le temps. L'implémentation Python est quelque chose comme:
x += 5
comme notation abrégée pour x = x + 5
.
Mais pourquoi est-ce considéré comme une bonne pratique? Je l'ai retrouvé dans presque tous les livres ou tutoriels de programmation que j'ai lus pour Python, C, R, etc. Je comprends que c'est pratique, en économisant trois frappes, espaces compris. Mais ils semblent toujours me faire trébucher quand je lis du code, et du moins le rendre moins lisible, pas plus.
Me manque-t-il une raison claire et évidente pour laquelle ils sont utilisés partout?
programming-practices
Fomite
la source
la source
x += 5
quex = x + 5
? Ou est-ce vraiment juste du sucre syntaxique comme vous le suggérez?Réponses:
Ce n'est pas un raccourci.
Le
+=
symbole est apparu dans le langage C dans les années 1970 et - avec l’idée C d’assembleur intelligent, correspond à une instruction machine et à un mode d’adressage nettement différents:Des choses comme "
i=i+1
","i+=1
"et"++i
", bien qu’à un niveau abstrait produisent le même effet, correspondent à un niveau bas à une manière différente de travailler du processeur.En particulier ces trois expressions, en supposant que la
i
variable réside dans l'adresse de la mémoire stockée dans un registre de la CPU (appelons-laD
- pensez à un "pointeur sur int") et que l' ALU du processeur prend un paramètre et renvoie le résultat sous forme de "accumulateur" (appelons-le A - pensez-y comme un int).Avec ces contraintes (très courantes dans tous les microprocesseurs de cette période), la traduction sera probablement
La première façon de procéder est non optimale, mais elle est plus générale lorsque vous utilisez des variables au lieu de constantes (
ADD A, B
ouADD A, (D+x)
) ou lorsque vous traduisez des expressions plus complexes (elles se résument toutes en une opération push de priorité basse dans une pile, appelez la priorité élevée, pop et répétez jusqu'à ce que tous les arguments aient été éliminés).La seconde est plus typique de "machine à états": nous ne sommes plus "en train d'évaluer une expression", mais "d'utiliser une valeur": nous utilisons toujours l'ALU, mais nous évitons de déplacer des valeurs car le résultat permettait de remplacer le paramètre. Ce type d'instruction ne peut pas être utilisé lorsque des expressions plus complexes sont nécessaires:
i = 3*i + i-2
ne peut pas être utilisé sur place, car ili
est requis plusieurs fois.Le troisième - même plus simple - n’envisage même pas l’idée «d’addition», mais utilise un circuit plus «primitif» (au sens de calcul) pour un compteur. L'instruction est court-circuitée, se charge plus rapidement et s'exécute immédiatement, car le réseau combinatoire requis pour moderniser un registre afin d'en faire un compteur est plus petit et donc plus rapide que celui d'un additionneur complet.
Avec les compilateurs contemporains (voir C, à présent), permettant l'optimisation du compilateur, la correspondance peut être permutée en fonction de la commodité, mais il existe toujours une différence conceptuelle dans la sémantique.
x += 5
veux direMais
x = x + 5
signifie:Bien sûr, l'optimisation peut
&x
place de l'accumulateurfaisant ainsi coïncider le code optimisé avec celui-
x += 5
ci.Mais cela ne peut être fait que si "trouver x" n'a pas d'effets secondaires, sinon
et
sont sémantiquement différentes, puisque
x()
les effets secondaires (admettrex()
est une fonction de faire des choses étranges et de renvoyer unint*
) seront produits deux fois ou une fois.L'équivalence entre
x = x + y
etx += y
est donc due au cas particulier où+=
et=
est appliquée à une valeur l directe.Pour passer à Python, il a hérité de la syntaxe de C, mais comme il n'y a pas de traduction / optimisation AVANT l'exécution dans des langages interprétés, les choses ne sont pas nécessairement intimement liées (puisqu'il y a une étape d'analyse de moins). Cependant, un interprète peut faire référence à différentes routines d'exécution pour les trois types d'expression, en tirant parti d'un code machine différent en fonction de la manière dont l'expression est formée et du contexte d'évaluation.
Pour qui aime plus de détail ...
Chaque unité centrale a une unité ALU (unité arithmétique-logique) qui est, dans son essence même, un réseau combinatoire dont les entrées et les sorties sont "branchées" sur les registres et / ou en mémoire en fonction du code opération de l'instruction.
Les opérations binaires sont généralement implémentées en tant que "modificateur d’un registre accumulateur avec une entrée prise" quelque part ", où quelque part peut se trouver - dans le flux d’instructions lui-même (typique pour le contant manifeste: ADD A 5) - dans un autre registre temporaries: par exemple ADD AB) - dans la mémoire, à une adresse donnée par un registre (typique de la récupération de données, par exemple: ADD A (H)) - H, dans ce cas, fonctionne comme un pointeur de déréférencement.
Avec ce pseudocode,
x += 5
estalors que
x = x+5
estC'est-à-dire que x + 5 donne un temporaire qui est assigné ultérieurement.
x += 5
opère directement sur x.L'implémentation réelle dépend du jeu d'instructions réel du processeur: s'il n'y a pas de
ADD (.) c
code opération, le premier code devient le second: aucun moyen.S'il existe un tel opcode et que l'optimisation est activée, la seconde expression, après avoir éliminé les déplacements inversés et ajusté l'opcode des registres, devient la première.
la source
Selon votre façon de penser, il est en fait plus facile à comprendre car plus simple. Prends pour exemple:
x = x + 5
invoque le traitement mental de "take x, ajoute-en cinq, puis assigne cette nouvelle valeur à x"x += 5
peut être considéré comme "augmenter x de 5"Donc, ce n'est pas juste un raccourci, il décrit en fait la fonctionnalité beaucoup plus directement. Lors de la lecture de morceaux de code, il est beaucoup plus facile à comprendre.
la source
x = x + 5
me perturbait toujours. Quand j’ai commencé à apprendre les mathématiques à un âge plus avancé, cela me dérangeait encore plus. L'utilisationx += 5
est beaucoup plus descriptive et prend beaucoup plus de sens en tant qu'expression.reallyreallyreallylongvariablename = reallyreallyreallylongvariablename + 1
... oh non !!! une faute de frappeAu moins en Python ,
x += y
etx = x + y
peut faire des choses complètement différentes.Par exemple, si nous faisons
alors
a += [3]
se traduira para == b == [3]
, tandis quea = a + [3]
se traduira para == [3]
etb == []
. En d’autres+=
termes , modifie l’objet sur place (enfin, vous pouvez définir la__iadd__
méthode pour faire à peu près tout ce que vous voulez), tout en=
créant un nouvel objet et en y associant la variable.Ceci est très important lorsque vous travaillez avec NumPy , car vous vous retrouvez souvent avec plusieurs références à différentes parties d'un tableau, et il est important de vous assurer de ne pas modifier par inadvertance une partie d'un tableau qui comporte d'autres références, ou copier inutilement des tableaux (ce qui peut être très coûteux).
la source
__iadd__
: il y a des langues où vous pouvez créer une référence immuable à une structure de données mutable, oùoperator +=
est défini, par exemple scala:val sb = StringBuffer(); lb += "mutable structure"
vsvar s = ""; s += "mutable variable"
. l'autre modifie le contenu de la structure de données tandis que cette dernière fait pointer la variable sur une nouvelle.Cela s'appelle un idiome . Les idiomes de programmation sont utiles car ils constituent un moyen cohérent d’écrire une structure de programmation particulière.
Chaque fois que quelqu'un écrit,
x += y
vous savez qu'ilx
est incrémenté pary
et non par une opération plus complexe (en tant que meilleure pratique, en règle générale, je ne mélangerais pas d'opérations plus complexes et ces raccourcis de syntaxe). Cela est le plus logique lorsque vous incrémentez de 1.la source
++x
etx+=1
sont équivalents en C et Java (peut-être aussi en C #), mais pas nécessairement en C ++ en raison de la sémantique complexe des opérateurs. L'essentiel est qu'ils évaluent tous les deuxx
une fois, incrémentent la variable d'une unité et produisent un résultat correspondant au contenu de la variable après l'évaluation.++x + 3
n'est donc pas la même chose quex += 1 + 3
. Entre parenthèses lex += 1
et c'est identique. En tant que déclarations par elles-mêmes, elles sont identiques.++x + 3
,x += 1 + 3
ou(x += 1) + 3
n'a un comportement indéfini (en supposant que la valeur résultante "s'adapte").Pour clarifier un peu le propos de @ Pubby, considérons
someObj.foo.bar.func(x, y, z).baz += 5
Sans
+=
opérateur, il y a deux façons de faire:someObj.foo.bar.func(x, y, z).baz = someObj.foo.bar.func(x, y, z).baz + 5
. Ce n'est pas seulement terriblement redondant et long, c'est aussi plus lent. Par conséquent, il faudraittmp := someObj.foo.bar.func(x, y, z); tmp.baz = tmp.bar + 5
. C'est bon, mais c'est très bruyant pour une chose simple. C’est en fait très proche de ce qui se passe au moment de l’exécution, mais il est fastidieux d’écrire et le simple fait d’utiliser+=
déplacera le travail vers le compilateur / interprète.L’avantage de
+=
ces opérateurs est indéniable, mais s’y habituer n’est qu’une question de temps.la source
C’est vrai que c’est plus court et plus simple, et c’est vrai que cela a probablement été inspiré par le langage d’assemblage sous-jacent, mais la pratique recommandée est qu’il empêche toute classe d’erreurs et facilite la révision du code et la sécurité. ce qu'il fait.
Avec
Comme il n'y a qu'un seul nom de variable impliqué, vous êtes sûr de ce que fait l'instruction.
Avec
RidiculouslyComplexName = RidiculosulyComplexName + 1;
Il y a toujours des doutes sur le fait que les deux côtés sont exactement les mêmes. Avez-vous vu le bug? La situation est encore pire lorsque des indices et des qualificatifs sont présents.
la source
Bien que la notation + = soit idiomatique et plus courte, ce n’est pas pour cette raison qu’elle est plus facile à lire. La partie la plus importante du code de lecture est la correspondance de la syntaxe avec le sens. Ainsi, plus la syntaxe correspond aux processus de pensée du programmeur, plus elle sera lisible (c'est aussi la raison pour laquelle le code standard est mauvais: il ne fait pas partie des idées processus, mais toujours nécessaire pour que le code fonctionne). Dans ce cas, la pensée est "incrémenter la variable x de 5", et non "que x soit la valeur de x plus 5".
Il existe d'autres cas où une notation courte est mauvaise pour la lisibilité, par exemple lorsque vous utilisez un opérateur ternaire pour lequel une
if
instruction serait plus appropriée.la source
Pour comprendre pourquoi ces opérateurs sont d’abord dans les langues de «style C», voici un extrait de K & R 1st Edition (1978), il y a 34 ans:
Je pense qu'il ressort clairement de ce passage que Brian Kernighan et Dennis Ritchie (K & R) pensaient que les opérateurs d'assignation de composé contribuaient à la lisibilité du code.
Cela fait longtemps que K & R a écrit cela, et bon nombre des «meilleures pratiques» concernant la manière dont les utilisateurs doivent écrire du code ont changé ou évolué depuis. Mais cette question programmers.stackexchange est la première fois que je me souviens de quelqu'un qui se plaignait de la lisibilité des assignations composées. Je me demande donc si de nombreux programmeurs trouvent qu’elles posent problème. Là encore, alors que je tape ceci, la question a 95 votes positifs, alors peut-être que les gens les trouveront bouleversés lors de la lecture du code.
la source
Outre la lisibilité, ils font en réalité différentes choses: ils n'ont
+=
pas à évaluer son opérande gauche deux fois.Par exemple,
expr = expr + 5
evalauteexpr
deux fois (en supposant que ceexpr
soit impur).la source
expr = expr + 5
etexpr += 5
expr
a des effets secondaires.expr
a des effets secondaires, vousexpr = expr + 5
devez les invoquer deux fois.volatile
sont des effets secondaires, etx=x+5
etx+=5
ont les mêmes effets secondaires quandx
estvolatile
Outre les avantages évidents que d'autres personnes ont très bien décrits, lorsque vous avez des noms très longs, il est plus compact.
ou
la source
C'est concis.
C'est beaucoup plus court pour taper. Cela implique moins d'opérateurs. Il a moins de surface et moins de risque de confusion.
Il utilise un opérateur plus spécifique.
C'est un exemple artificiel, et je ne suis pas sûr que les compilateurs actuels l'implémentent. x + = y utilise en fait un argument et un opérateur et modifie x en place. x = x + y pourrait avoir une représentation intermédiaire de x = z où z est x + y. Ce dernier utilise deux opérateurs, addition et affectation, et une variable temporaire. L'opérateur unique explique très clairement que le côté de la valeur ne peut être autre que y et qu'il n'a pas besoin d'être interprété. Et il pourrait théoriquement exister un processeur sophistiqué doté d'un opérateur plus égal à égal à un opérateur plus rapide et d'un opérateur d'affectation en série.
la source
ADD
instructions de nombreuses CPU ont des variantes qui agissent directement sur les registres ou la mémoire en utilisant d’autres registres, mémoire ou constantes comme deuxième ajout. Toutes les combinaisons ne sont pas disponibles (par exemple, ajouter de la mémoire à la mémoire), mais elles sont suffisantes pour être utiles. En tout état de cause, tout compilateur doté d'un optimiseur décent saura générer le même code pour la mêmex = x + y
raisonx += y
.C'est un beau langage. Que ce soit plus rapide ou non dépend de la langue. En C, c'est plus rapide car cela se traduit par une instruction pour augmenter la variable par le côté droit. Les langages modernes, y compris Python, Ruby, C, C ++ et Java, prennent tous en charge la syntaxe op =. Il est compact et vous vous y habituez rapidement. Comme vous le verrez beaucoup dans le code des autres peuples (OPC), vous pouvez aussi vous y habituer et l'utiliser. Voici ce qui se passe dans quelques autres langues.
En Python, le typage
x += 5
provoque toujours la création de l'objet entier 1 (bien qu'il puisse être tiré d'un pool) et l'orphelin de l'objet entier contenant 5.En Java, cela provoque une distribution tacite. Essayez de taper
la source
x+=5
a aussi peu de signification quex=x+5
; par exemple dans Haskell celui - ci ne pas provoquerx
d'être incrémenté de 5 - au lieu qu'elle engage une boucle de récursivité infinie. Qui voudrait un raccourci pour cela?+=
dépend moins de la langue que du processeur . Par exemple, X86 est une architecture à deux adresses, il ne supporte que+=
nativement. Une déclaration telle quea = b + c;
doit être compiléea = b; a += c;
car il n’ya simplement aucune instruction qui puisse placer le résultat de l’addition ailleurs que dans la place de l’un des sommands. L’architecture Power, en revanche, est une architecture à trois adresses sans commandes spéciales+=
. Sur cette architecture, les instructionsa += b;
eta = a + b;
compilent toujours au même code.Des opérateurs tels que
+=
sont très utiles lorsque vous utilisez une variable comme accumulateur , c'est-à-dire un total cumulé:Est beaucoup plus facile à lire que:
Dans le premier cas, conceptuellement, vous modifiez la valeur dans
x
. Dans le second cas, vous calculez une nouvelle valeur et l'attribuez àx
chaque fois. Et même si vous n’écririez probablement jamais un code aussi simple, l’idée reste la même… l’accent est mis sur ce que vous faites pour une valeur existante au lieu de créer une nouvelle valeur.la source
Considère ceci
D0 tu veux vraiment écrire
la source
Les autres réponses ciblent les cas les plus courants, mais il existe une autre raison: dans certains langages de programmation, il peut être surchargé; par exemple Scala .
Petite leçon de scala:
Si une classe ne définit que l’
+
opérateur,x+=y
c’est bien un raccourci dex=x+y
.Si une classe est surchargée
+=
, cependant, ils ne sont pas:De plus, les opérateurs
+
et+=
sont deux opérateurs distincts (et pas seulement ceux-ci: + a, ++ a, a ++, a + ba + = b sont également des opérateurs différents); dans les langues où la surcharge d'opérateur est disponible, cela peut créer des situations intéressantes. Tout comme décrit ci-dessus - si vous surchargez l'+
opérateur pour effectuer l'ajout, n'oubliez pas qu'il+=
faudra également le surcharger.la source
+=
, puis de définira+b
comme "faire une copie dea
, mettreb
dessus en utilisant+=
, retourner la copie dea
".Dites-le une fois et une fois seulement: à l'
x = x + 1
intérieur, je dis deux fois «x».Mais n'écrivez jamais: 'a = b + = 1' ou nous devrons tuer 10 chatons, 27 souris, un chien et un hamster.
Vous ne devriez jamais changer la valeur d'une variable, car il est plus facile de prouver que le code est correct - voir Programmation fonctionnelle. Cependant, si vous le faites, il vaut mieux ne pas dire les choses une seule fois.
la source