Pourquoi n'y a-t-il pas d'opérateurs ++
et --
en Python?
Ce n'est pas parce que ça n'a pas de sens; il est parfaitement logique de définir "x ++" comme "x + = 1, en évaluant la liaison précédente de x".
Si vous voulez connaître la raison initiale, vous devrez soit parcourir les anciennes listes de diffusion Python, soit demander à quelqu'un qui était présent (par exemple, Guido), mais il est assez facile de le justifier après coup:
L'incrémentation et la décrémentation simples ne sont pas nécessaires autant que dans d'autres langues. Vous n'écrivez pas des choses comme for(int i = 0; i < 10; ++i)
en Python très souvent; au lieu de cela, vous faites des choses comme for i in range(0, 10)
.
Comme il n'est pas nécessaire presque aussi souvent, il y a beaucoup moins de raisons de lui donner sa propre syntaxe spéciale; Lorsque vous avez besoin d'incrémenter, +=
convient généralement très bien.
Ce n'est pas une décision de savoir si cela a un sens, ou si cela peut être fait - c'est le cas, et cela est possible. La question est de savoir si l'avantage mérite d'être ajouté à la syntaxe principale du langage. Rappelez-vous qu’il s’agit de quatre opérateurs - postinc, postdec, preinc, predec, et que chacun d’eux doit avoir sa propre surcharge de classe; ils doivent tous être spécifiés et testés; cela ajouterait des opcodes à la langue (impliquant un moteur plus gros et donc plus lent VM); chaque classe prenant en charge un incrément logique aurait besoin de les implémenter (en plus de +=
et -=
).
Tout cela est redondant avec +=
et -=
, donc cela deviendrait une perte nette.
Cette réponse originale que j'ai écrite est un mythe du folklore de l'informatique : critiqué par Dennis Ritchie comme "historiquement impossible", comme indiqué dans les lettres aux rédacteurs en chef de Communications de l'ACM juillet 2012 doi: 10.1145/2209249.2209251
Les opérateurs d’incrémentation/décrémentation C ont été inventés à une époque où le compilateur C n’était pas très intelligent et où les auteurs voulaient pouvoir spécifier l’intention directe qu’un opérateur de langage machine soit utilisé, ce qui économisait une poignée de cycles pour un compilateur. pourrait faire un
load memory
load 1
add
store memory
au lieu de
inc memory
et le PDP-11 a même pris en charge les instructions "auto-incrémentation" et "auto-incrémentation différée" correspondant à *++p
et *p++
, respectivement. Voir la section 5.3 de le manuel si horriblement curieux.
Comme les compilateurs sont assez intelligents pour gérer les astuces d’optimisation de haut niveau intégrées à la syntaxe de C, ils ne sont plus qu’un confort syntaxique.
Python n'a pas d'astuces pour transmettre des intentions à l'assembleur car il n'en utilise pas.
J'ai toujours supposé que cela avait à voir avec cette ligne du zen de python:
Il devrait y avoir un - et de préférence un seul - moyen évident de le faire.
x ++ et x + = 1 font exactement la même chose, il n'y a donc aucune raison d'avoir les deux.
Bien sûr, nous pourrions dire "Guido vient de prendre cette décision", mais je pense que la question porte vraiment sur les raisons de cette décision. Je pense qu'il y a plusieurs raisons:
Parce que, en Python, les entiers sont immuables (int's = = renvoie en fait un objet différent).
De plus, avec ++/- vous devez vous préoccuper de l'incrément/décrément avant/après, et il ne faut qu'une frappe de plus pour écrire x+=1
. En d'autres termes, cela évite une confusion potentielle au détriment d'un gain minime.
Python est très lié à clarté et aucun programmeur n’est susceptible de deviner correctement la signification de --a
sauf s’il a appris un langage possédant cette construction.
Python traite également beaucoup de éviter les constructions qui invitent les erreurs et les opérateurs ++
sont connus pour être de riches sources de défauts . Ces deux raisons suffisent pour ne pas avoir ces opérateurs en Python.
La décision selon laquelle Python utilise l'indentation pour marquer des blocs plutôt que des moyens syntaxiques tels qu'une forme de début/fin entre crochets .__ ou un marquage de fin obligatoire repose en grande partie sur les mêmes considérations.
Pour illustrer cela, jetez un œil à la discussion concernant l’introduction d’un opérateur conditionnel (dans C: cond ? resultif : resultelse
) dans Python en 2005 . Lisez au moins le premier message et le décision message de cette discussion (qui avait précédemment plusieurs précurseurs sur le même sujet).
Trivia: Le PEP fréquemment mentionné est la "proposition d'extension Python" PEP 308 . LC signifie compréhension de la liste , GE signifie expression génératrice (et ne vous inquiétez pas si cela vous confond, ils ne font pas partie des rares taches compliquées de Python).
C'était juste conçu comme ça. Les opérateurs d’incrémentation et de décrémentation ne sont que des raccourcis vers x = x + 1
. Python a généralement adopté une stratégie de conception qui réduit le nombre de moyens alternatifs permettant d'effectuer une opération. L'affectation augmentée est la chose la plus proche des opérateurs d'incrémentation/décrémentation en Python.
Je suis très novice en python, mais je suppose que la raison en est l’accent mis sur les objets mutables et immuables dans le langage. Maintenant, je sais que x ++ peut facilement être interprété comme x = x + 1, mais il semble que vous augmentez in-situ un objet qui pourrait être immuable.
Juste mon estimation/sentiment/intuition.
Voici comment on comprend pourquoi python n’a pas l’opérateur ++
: Lorsque vous écrivez ceci en python a=b=c=1
, vous obtiendrez trois variables (étiquettes) pointant vers le même objet (dont la valeur est 1). Vous pouvez le vérifier en utilisant la fonction id qui retournera une adresse de mémoire d'objet:
In [19]: id(a)
Out[19]: 34019256
In [20]: id(b)
Out[20]: 34019256
In [21]: id(c)
Out[21]: 34019256
Les trois variables (étiquettes) désignent le même objet. Maintenant, incrémentez l’une des variables et voyez comment elle affecte les adresses mémoire:
In [22] a = a + 1
In [23]: id(a)
Out[23]: 34019232
In [24]: id(b)
Out[24]: 34019256
In [25]: id(c)
Out[25]: 34019256
Vous pouvez voir que la variable a
pointe maintenant vers un autre objet en tant que variables b
et c
. Parce que vous avez utilisé a = a + 1
, il est explicitement clair. En d'autres termes, vous affectez complètement un autre objet à l'étiquette a
. Imaginez que vous puissiez écrire a++
, cela suggérerait que vous n’ayez pas assigné à la variable a
nouvel objet, mais que vous avez incrémenté l’ancien. Tout cela est IMHO pour minimiser la confusion. Pour mieux comprendre, voir comment fonctionnent les variables python:
Python est-il appel par valeur ou appel par référence? Ni.
Python passe-t-il par valeur ou par référence?
Python est-il passe-à-référence ou passe-à-valeur?
Python: Comment passer d'une variable par référence?
Compréhension des variables Python et de la gestion de la mémoire
Emulation du comportement passage par valeur en python
Premièrement, Python n’est influencé que indirectement par C; il est fortement influencé par ABC , qui apparemment n'a pas ces opérateurs , il ne devrait donc pas y avoir de grande surprise à ne pas les trouver en Python non plus.
Deuxièmement, comme d’autres l’ont déjà dit, les incréments et décrémentations sont déjà pris en charge par +=
et -=
.
Troisièmement, la prise en charge complète d’un ensemble d’opérateurs ++
et --
inclut généralement la prise en charge de leurs versions préfixe et postfixe. En C et C++, cela peut conduire à toutes sortes de "belles" constructions qui me semblent aller à l'encontre de l'esprit de simplicité et de franchise que Python embrasse.
Par exemple, alors que l'instruction C while(*t++ = *s++);
peut sembler simple et élégante à un programmeur expérimenté, à quelqu'un qui l'apprend, elle est tout sauf simple. Ajoutez une combinaison d'incréments et de diminutions de préfixes et de postfixes, et même de nombreux professionnels devront s'arrêter et réfléchir un peu.
Je pense que cela découle du credo Python selon lequel "explicite vaut mieux qu'implicite".
Cela est peut-être dû au fait que @GlennMaynard examine la question comme si elle était comparée à d’autres langues, mais en Python, vous faites les choses à la manière de Python. Ce n'est pas une question de "pourquoi". C'est là et vous pouvez faire les choses dans le même sens avec x+=
. Dans Le zen de Python , il est indiqué: "il ne devrait y avoir qu'un seul moyen de résoudre un problème." Les choix multiples sont excellents dans l’art (liberté d’expression) mais médiocres en ingénierie.
La classe d'opérateurs ++
est une expression avec des effets secondaires. C'est quelque chose que l'on ne trouve généralement pas dans Python.
Pour la même raison, une affectation n'est pas une expression en Python, empêchant ainsi l'idiot if (a = f(...)) { /* using a here */ }
commun.
Enfin, je soupçonne que leurs opérateurs ne sont pas très compatibles avec la sémantique de référence de Pythons. N'oubliez pas que Python n'a pas de variables (ou de pointeurs) avec la sémantique connue de C/C++.
comme je l’ai compris, vous ne penserez donc pas que la valeur en mémoire est modifiée . en c lorsque vous effectuez x ++, la valeur de x en mémoire change . mais en python, tous les nombres sont immuables d’où l’adresse indiquée par x comme toujours a x pas x + 1. quand vous écrivez x ++, vous penserez que x change réellement ce qui se passe, c’est que x refrence est changé en un emplacement en mémoire où x + 1 est stocké ou recréez cet emplacement si ce n’est pas le cas.
Peut-être une meilleure question serait-elle de se demander pourquoi ces opérateurs existent en C. Les appels de K & R incrémentent et décrémentent les opérateurs "inhabituels" (Section 2.8page 46). L'introduction les appelle «plus concis et souvent plus efficace». Je soupçonne que le fait que ces opérations apparaissent toujours lors de la manipulation de pointeurs a également joué un rôle dans leur introduction. test en C, et il semblerait que l’assemblée générée par gcc utilise addl au lieu de incl dans les deux cas) et qu’il n’existe pas d’arithmétique de pointeur; Donc, cela aurait été juste une autre façon de le faire et nous savons que Python déteste ça.
Je sais qu'il s'agit d'un ancien thread, mais le cas d'utilisation le plus courant pour ++ i n'est pas couvert, à savoir le fait d'indexer manuellement des ensembles lorsqu'il n'y a pas d'index fourni. C'est la raison pour laquelle python fournit enumerate ()
Exemple: dans une langue donnée, lorsque vous utilisez une construction telle que foreach pour effectuer une itération sur un ensemble, nous allons même dire que c'est un ensemble non ordonné et que vous avez besoin d'un index unique pour tout différencier, par exemple.
i = 0
stuff = {'a': 'b', 'c': 'd', 'e': 'f'}
uniquestuff = {}
for key, val in stuff.items() :
uniquestuff[key] = '{0}{1}'.format(val, i)
i += 1
Dans ce cas, python fournit une méthode enumerate, par exemple.
for i, (key, val) in enumerate(stuff.items()) :
Pour compléter déjà de bonnes réponses sur cette page:
Supposons que nous décidions de le faire, préfixe (++i
) qui romprait les opérateurs unaires + et -.
Aujourd'hui, préfixer par ++
ou --
ne fait rien, car il permet à l'opérateur unaire plus deux fois (ne fait rien) ou unaire moins deux fois (deux fois: s'annule)
>>> i=12
>>> ++i
12
>>> --i
12
Cela risquerait donc de briser cette logique.
Je pense que cela concerne les concepts de mutabilité et d'immutabilité des objets. 2,3,4,5 sont immuables en python. Reportez-vous à l'image ci-dessous. 2 a fixé id jusqu'à ce processus python.
x ++ signifierait essentiellement un incrément sur place tel que C. En C, x ++ effectue des incréments sur place. Ainsi, x = 3 et x ++ incrémenteraient 3 dans la mémoire jusqu'à 4, contrairement au python où 3 existeraient encore en mémoire.
Ainsi, en python, vous n'avez pas besoin de recréer une valeur en mémoire. Cela peut conduire à des optimisations de performances.
Ceci est une réponse basée sur l'intuition.