Pourquoi n'y a-t-il pas d'opérateurs ++ et - en Python?

Réponses:

443

Ce n'est pas parce que cela 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 d'origine, vous devrez soit parcourir les anciennes listes de diffusion Python ou demander à quelqu'un qui était là (par exemple, Guido), mais c'est assez facile à 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).

Puisqu'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'augmenter, +=c'est généralement très bien.

Ce n'est pas une décision de savoir si cela a du sens, ou si cela peut être fait - il le fait, et il le peut. Il s'agit de savoir si l'avantage vaut la peine d'être ajouté à la syntaxe de base du langage. N'oubliez pas qu'il s'agit de quatre opérateurs - postinc, postdec, preinc, predec, et chacun d'entre eux aurait besoin d'avoir ses propres surcharges de classe; ils doivent tous être spécifiés et testés; cela ajouterait des opcodes au langage (impliquant un moteur VM plus grand, et donc plus lent); chaque classe qui prend en charge un incrément logique devrait les implémenter (en plus de +=et -=).

Tout cela est redondant avec +=et -=, ce serait donc une perte nette.

Glenn Maynard
la source
98
Il est souvent utile d'utiliser quelque chose comme array [i ++], ce qui n'est pas bien fait avec + = / - =.
Turner Hayes
102
@thayes: Ce n'est pas un modèle courant en Python.
Glenn Maynard
9
@thayes Puisque ce sera à l'intérieur d'une boucle, vous pouvez aussi bien boucler idirectement - si vous en avez réellement besoin et ne pouvez pas, par exemple, utiliserarray.append()
Tobias Kienzler
31
Je vois que la préoccupation beaucoup plus importante est la lisibilité et la prévisibilité. Dans mes jours C, j'ai vu plus qu'assez de bugs résultant de malentendus sur la distinction entre i++et ++i...
Charles Duffy
5
Ajoutant à la justification après coup: sur un projet sur lequel je travaille, j'ai rencontré (plus que quiconque au cours de leur vie) une bonne quantité de code C ++ souffrant de problèmes avec ++et --utilisé de manière à aboutir à des définitions indéfinies ou non spécifiées. comportement. Ils permettent d'écrire du code compliqué et difficile à analyser correctement.
Brian Vandenberg
84

Cette réponse originale que j'ai écrite est un mythe du folklore de l'informatique : démystifié par Dennis Ritchie comme "historiquement impossible" comme indiqué dans les lettres aux rédacteurs des 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 les auteurs voulaient pouvoir spécifier l'intention directe qu'un opérateur en langage machine soit utilisé, ce qui permettait d'économiser une poignée de cycles pour un compilateur qui pourrait faire un

load memory
load 1
add
store memory

au lieu de

inc memory 

et le PDP-11 supportait même les instructions "auto-incrémentation" et "auto-incrémentation différée" correspondant respectivement à *++pet *p++. Voir section 5.3 du 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'une commodité syntaxique.

Python n'a pas d'astuces pour transmettre des intentions à l'assembleur car il n'en utilise pas.

msw
la source
4
Javascript a ++. Je ne pense pas que ce soit une «astuce pour transmettre des intentions à l'assembleur». De plus, Python a un bytecode. Je pense donc que la raison est autre chose.
Nathan Davis
13
Cette activité de "fourniture d'indices au compilateur" est en effet un mythe. Franchement, c'est un ajout stupide à n'importe quelle langue et il viole les deux préceptes suivants: 1. Vous ne codez pas pour que l'ordinateur lise, vous codez pour qu'un autre ingénieur lise. Et 2. Vous ne codez pas pour qu'un ingénieur compétent lise, vous codez pour un ingénieur compétent pour lire tout épuisé à 3 heures du matin et sauté sur la caféine.
3
@ tgm1024 Pour être honnête, lorsque vous codez sur un télétype semi-duplex de 10 à 30 caractères par seconde, vous codez pour pouvoir le saisir avant la semaine prochaine.
msw
4
@ tgm1024 Unix et C ont vu l'essentiel de leur développement initial sur des PDP-11 qui utilisaient des télétypes incroyablement lents pour la communication avec les utilisateurs. Alors que vous avez tout à fait raison de dire qu'aujourd'hui le codage de la machine est presque stupide, à l'époque c'était l'interface Homme / Machine qui était le goulot d'étranglement. Il est difficile d'imaginer travailler aussi lentement si jamais vous ne le deviez.
msw
65

J'ai toujours supposé que cela avait à voir avec cette ligne du zen de python:

Il devrait y avoir une - et de préférence une seule - manière évidente de le faire.

x ++ et x + = 1 font exactement la même chose, il n'y a donc aucune raison d'avoir les deux.

GSto
la source
10
one--est zéro ?
Andre Holzner
25
one--est un dans la phrase, mais zéro immédiatement après. Donc, ce «koan» laisse également entendre que les opérateurs d'incrémentation / décrémentation ne sont pas évidents.
Victor K
14
@EralpB Si vous supprimez + =, vous ne pouvez pas faire des choses comme x + = 10. + = est un cas plus général de ++
Rory
8
Aussi: "Explicit vaut mieux qu'implicite".
Ber
2
Certainement pas la même chose, car x + = 1 n'est PAS une expression - c'est une déclaration - et elle n'évalue rien. Vous ne pouvez pas faire des choses comme: 'row [col ++] = a; ligne [col ++] = b '. Sans parler des éléments pré-inc et post-inc de c ++.
Uri
38

Bien sûr, nous pourrions dire "Guido vient de décider de cette façon", mais je pense que la question porte vraiment sur les raisons de cette décision. Je pense qu'il y a plusieurs raisons:

  • Il mélange des déclarations et des expressions, ce qui n'est pas une bonne pratique. Voir http://norvig.com/python-iaq.html
  • Il encourage généralement les gens à écrire du code moins lisible
  • Une complexité supplémentaire dans l'implémentation du langage, qui n'est pas nécessaire en Python, comme déjà mentionné
EMP
la source
12
Heureux que quelqu'un ait finalement mentionné l'aspect déclaration vs expression. En C, l'affectation est une expression et donc l'opérateur ++. En Python, l'affectation est une instruction, donc si elle avait un ++, elle devrait probablement être une instruction d'affectation également (et encore moins utile ou nécessaire).
martineau
D'accord - s'il s'agissait de déclarations, il serait alors tout à fait inutile de parler de la différence entre les post-opérateurs et les pré-opérateurs.
Crowman
17

Parce que, en Python, les entiers sont immuables (int + + renvoie en fait un objet différent).

De plus, avec ++ / -, vous devez vous soucier de la pré-incrémentation et de la décroissance post-incrémentation, et cela ne prend qu'une touche de plus pour écrire x+=1. En d'autres termes, cela évite toute confusion potentielle au détriment de très peu de gain.

Nathan Davis
la source
les ints sont également immuables en C. Si vous ne le pensez pas, essayez d'obtenir votre compilateur C pour générer du code pour 42++... Quelque chose comme ça (modifier une constante littérale) était en fait possible dans certains anciens compilateurs Fortran (ou du moins j'ai lu): Toutes les utilisations futures de ce littéral dans cette exécution de programme aurait alors vraiment une valeur différente. Bon débogage!
Lutz Prechelt
10
Droite. 42 est une constante littérale . Les constantes sont (ou du moins devraient être) immuables. Cela ne signifie pas que les C inten général sont immuables. Un inten C désigne simplement une place dans la mémoire. Et les bits à cet endroit sont très variables. Vous pouvez, par exemple, créer une référence à un intet modifier le référent de cette référence. Cette modification est visible dans toutes les références (y compris la intvariable d' origine ) à cet endroit. Il n'en va pas de même pour un objet entier Python.
Nathan Davis
x + = 1 ne finit pas par devenir inc mem. Python exécute un appel de fonction pour ajouter 1 à une variable; C'est pathétique.
PalaDolphin
12

Clarté!

Python est beaucoup de clarté et aucun programmeur n'est susceptible de deviner correctement la signification de--a moins qu'il / elle ait appris un langage ayant cette construction.

Python consiste également à éviter les constructions qui invitent à des erreurs et à++ 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 les blocs plutôt que des moyens syntaxiques tels qu'une certaine forme de bracketing de début / fin ou de marquage de fin obligatoire est basée en grande partie sur les mêmes considérations.

Par exemple, jetez un œil à la discussion sur l'introduction d'un opérateur conditionnel (en C cond ? resultif : resultelse:) dans Python en 2005. Lisez au moins le premier message et le message de décision de cette discussion (qui avait précédemment plusieurs précurseurs sur le même sujet).

Anecdote: Le PEP fréquemment mentionné est le PEP 308 "Proposition d'extension Python" . LC signifie compréhension de liste , GE signifie expression de générateur (et ne vous inquiétez pas si ceux-ci vous confondent, ce ne sont pas les rares endroits compliqués de Python).

Lutz Prechelt
la source
10

Ma compréhension de pourquoi python n'a pas d' ++opérateur est la suivante: Lorsque vous écrivez ceci en python, a=b=c=1vous 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 renverra une adresse 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) pointent vers le même objet. Incrémentez maintenant une variable 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 cette variable apointe maintenant vers un autre objet en tant que variables bet c. Parce que vous l'avez utilisé, a = a + 1c'est clairement clair. En d'autres termes, vous attribuez complètement un autre objet à étiqueter a. Imaginez que vous puissiez l'écrire a++suggérerait que vous n'avez pas assigné à un anouvel objet variable mais que vous avez incrémenté l'ancien. Tout cela est à mon humble avis pour minimiser la confusion. Pour une meilleure compréhension, voyez comment fonctionnent les variables python:

En Python, pourquoi une fonction peut-elle modifier certains arguments tels que perçus par l'appelant, mais pas d'autres?

Python est-il appelé par valeur ou par référence? Ni.

Python passe-t-il par valeur ou par référence?

Python passe-t-il par référence ou passe-par-valeur?

Python: Comment passer une variable par référence?

Comprendre les variables Python et la gestion de la mémoire

Émulation du comportement passe-par-valeur en python

Les fonctions Python appellent par référence

Code comme un Pythonista: Python idiomatique

Wakan Tanka
la source
9

Il a juste été conçu de cette façon. Les opérateurs d'incrémentation et de décrémentation ne sont que des raccourcis pour x = x + 1. Python a généralement adopté une stratégie de conception qui réduit le nombre de moyens alternatifs pour 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, et ils n'ont même pas été ajoutés avant Python 2.0.

Reed Copsey
la source
3
Ouais mec, tu pourrais remplacer return a[i++]par return a[i=i+1].
Luís de Sousa
7

Je suis très nouveau sur python mais je soupçonne que la raison en est à cause de l'accent mis entre 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 incrémentez en place un objet qui pourrait être immuable.

Juste ma conjecture / sentiment / intuition.

mkoistinen
la source
Dans cet aspect, x++est plus proche x += 1que de x = x + 1, ces deux-là font également une différence sur les objets mutables.
glglgl
4

Premièrement, Python n'est qu'indirectement influencé par C; il est fortement influencé par ABC , qui n'a apparemment pas ces opérateurs , il ne devrait donc pas être surprenant de ne pas les trouver en Python.

En second lieu , comme d' autres l' ont dit, et incrément sont pris en charge par décrément +=et-= déjà.

Troisièmement, un support complet pour un ++et-- ensemble d'opérateurs inclut généralement la prise en charge des versions préfixe et postfixe de ceux-ci. En C et C ++, cela peut conduire à toutes sortes de "jolies" constructions qui semblent (à mes yeux) aller à l'encontre de l'esprit de simplicité et de franchise que Python embrasse.

Par exemple, bien que l'instruction C while(*t++ = *s++);puisse sembler simple et élégante à un programmeur expérimenté, à quelqu'un qui l'apprend, elle est tout sauf simple. Ajoutez un mélange d'incréments et de décréments de préfixe et de postfix, et même de nombreux pros devront s'arrêter et réfléchir un peu.

wberry
la source
3

Je crois que cela découle du credo de Python selon lequel "explicite vaut mieux qu'implicite".

Sepheus
la source
Eh bien, vous n'écrivez pas explicitement les instructions "begin" et "end" en Python, non? Même si je suis d'accord avec la déclaration, je pense qu'il y a des limites à cela. Bien que nous puissions discuter de ces limites, je pense que nous pouvons tous convenir qu’il existe une ligne qui n’est pas pratique à franchir. Et comme il y a tellement d'opinions et de justifications sur cette décision, je ne pense pas que ce soit un choix clair. Au moins, je ne trouve pas de source, où il est explicitement indiqué
Hasan Ammori
3

Cela peut être dû au fait que @GlennMaynard considère la question comme en comparaison avec d'autres langages, mais en Python, vous faites les choses à la manière de python. Ce n'est pas une question «pourquoi». Il est là et vous pouvez faire les choses avec le même effet x+=. Dans Le Zen de Python , il est dit: "il ne devrait y avoir qu'une seule façon de résoudre un problème." Les choix multiples sont grands en art (liberté d'expression) mais moche en ingénierie.

Nihal Sahu
la source
2

La ++classe d'opérateurs sont des expressions avec des effets secondaires. C'est quelque chose que l'on ne trouve généralement pas en Python.

Pour la même raison, une affectation n'est pas une expression en Python, empêchant ainsi l' if (a = f(...)) { /* using a here */ }idiome commun .

Enfin, je soupçonne qu'il n'y a pas d'opérateur très cohérent avec la sémantique de référence Pythons. N'oubliez pas que Python n'a pas de variables (ou pointeurs) avec la sémantique connue de C / C ++.

Ber
la source
1
rien n'empêche d'appeler une fonction avec un effet secondaire dans une compréhension test / expression / liste: f(a)aest une liste, un objet immuable.
Jean-François Fabre
1

Une meilleure question serait peut-être de se demander pourquoi ces opérateurs existent en C. K&R appelle les opérateurs d'incrémentation et de décrémentation «inhabituels» (section 2.8 page 46). L'introduction les appelle «plus concis et souvent plus efficaces». Je soupçonne que le fait que ces opérations se produisent toujours dans la manipulation de pointeurs a également joué un rôle dans leur introduction. En Python, il a probablement été décidé que cela n'avait aucun sens d'essayer d'optimiser les incréments (en fait, je viens de faire un test en C, et il semble que l'assembly généré par gcc utilise addl au lieu d'incl dans les deux cas) et il n'y a pas arithmétique du pointeur; il aurait donc été juste une façon de plus de le faire et nous savons que Python déteste cela.

Ludovico Fischer
la source
1

comme je l'ai compris, vous ne penserez donc pas que la valeur en mémoire est modifiée. en c lorsque vous faites x ++ la valeur de x en mémoire change. mais en python tous les nombres sont immuables d'où l'adresse que x pointait comme a toujours x pas x + 1. lorsque vous écrivez x ++, vous pensez que x change ce qui se passe réellement, c'est que la réfraction x est changée en un emplacement en mémoire où x + 1 est stocké ou recrée cet emplacement si la biche n'existe pas.

rafi wiener
la source
1
Alors, qu'est-ce qui rend cela ++différent de += 1?
Ber
1

Pour compléter des réponses déjà bonnes sur cette page:

Supposons que nous décidions de le faire, préfixe (++i ) qui briserait les opérateurs unaires + et -.

Aujourd'hui, le préfixe de ++ou --ne fait rien, car il active 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

Donc, cela pourrait potentiellement briser cette logique.

Jean-François Fabre
la source
1

D'autres réponses ont expliqué pourquoi ce n'est pas nécessaire pour les itérateurs, mais parfois il est utile lors de l'affectation d'augmenter une variable en ligne, vous pouvez obtenir le même effet en utilisant des tuples et une affectation multiple:

b = ++a devient:

a,b = (a+1,)*2

et b = a++devient:

a,b = a+1, a

Python 3.8 introduit l' :=opérateur d' affectation , ce qui nous permet de réaliser foo(++a)avec

foo(a:=a+1)

foo(a++) est toujours insaisissable.

JeffUK
la source
2
: = l'affectation est une honte
nehem
0

Je pense que cela se rapporte aux concepts de mutabilité et d'immuabilité des objets. 2,3,4,5 sont immuables en python. Reportez-vous à l'image ci-dessous. 2 a fixé l'id jusqu'à ce processus python.

ID des constantes et des variables

x ++ signifierait essentiellement un incrément sur place comme C. En C, x ++ effectue des incréments sur place. Ainsi, x = 3, et x ++ incrémenterait 3 en mémoire à 4, contrairement à python où 3 existerait toujours 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.

Pikesh Prasoon
la source
0

Je sais que c'est un vieux fil, mais le cas d'utilisation le plus courant pour ++ i n'est pas couvert, c'est-à-dire l'indexation manuelle des ensembles quand il n'y a pas d'index fournis. Cette situation est la raison pour laquelle python fournit enumerate ()

Exemple: dans une langue donnée, lorsque vous utilisez une construction comme foreach pour itérer sur un ensemble - pour l'exemple, nous dirons même que c'est un ensemble non ordonné et vous avez besoin d'un index unique pour tout les 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 des cas comme celui-ci, python fournit une méthode énumérée, par exemple

for i, (key, val) in enumerate(stuff.items()) :
Jessica Pennell
la source