¿Por qué no hay operadores ++ y - en Python?

Respuestas:

443

No es porque no tiene sentido; tiene perfecto sentido definir "x ++" como "x + = 1, evaluando el enlace anterior de x".

Si desea conocer la razón original, tendrá que leer las viejas listas de correo de Python o preguntarle a alguien que estuvo allí (por ejemplo, Guido), pero es bastante fácil justificar el hecho:

Incremento y decremento simples no son necesarios tanto como en otros idiomas. No escribes cosas como for(int i = 0; i < 10; ++i)en Python muy a menudo; en cambio haces cosas como for i in range(0, 10).

Como no se necesita con tanta frecuencia, hay muchas menos razones para darle su propia sintaxis especial; cuando necesita aumentar, +=generalmente está bien.

No es una decisión si tiene sentido o si se puede hacer, lo hace y puede. Se trata de si vale la pena agregar el beneficio a la sintaxis central del lenguaje. Recuerde, se trata de cuatro operadores: postinc, postdec, preinc, predec, y cada uno de estos necesitaría tener sus propias sobrecargas de clase; todos necesitan ser especificados y probados; agregaría códigos de operación al lenguaje (lo que implica un motor VM más grande y, por lo tanto, más lento); cada clase que admita un incremento lógico necesitaría implementarlos (además de +=y-= ).

Todo esto es redundante con +=y -=, por lo que se convertiría en una pérdida neta.

Glenn Maynard
fuente
98
A menudo es útil usar algo como array [i ++], que no se hace ordenadamente con + = / - =.
Turner Hayes
102
@thayes: Ese no es un patrón común en Python.
Glenn Maynard
99
@thayes Dado que eso estará dentro de un bucle, también podría ihacerlo directamente, si realmente lo necesita y no puede, por ejemplo, usarloarray.append()
Tobias Kienzler
31
Veo que la preocupación mucho mayor es la legibilidad y la previsibilidad. En mis días en C, vi más que suficientes errores derivados de malentendidos sobre la distinción entre i++y ++i...
Charles Duffy
55
Además de justificar después de los hechos: en un proyecto en el que trabajo, he encontrado (más de lo que nadie debería en su vida) una buena cantidad de código C ++ que sufre problemas ++y --se utiliza de manera indefinida o no especificada. comportamiento. Permiten escribir código complicado, difícil de analizar correctamente.
Brian Vandenberg
84

Esta respuesta original que escribí es un mito del folklore de la informática. : Dennis Ritchie lo desacredita como "históricamente imposible" como se señala en las cartas a los editores de Comunicaciones de la ACM Julio 2012 doi: 10.1145 / 2209249.2209251


Los operadores de incremento / decremento de C se inventaron en un momento en que el compilador de C no era muy inteligente y los autores querían poder especificar la intención directa de utilizar un operador de lenguaje de máquina que ahorrara un puñado de ciclos para un compilador que podría hacer un

load memory
load 1
add
store memory

en vez de

inc memory 

y el PDP-11 incluso admitía instrucciones de "autoincremento" y "autoincremento diferido" correspondientes a *++py*p++ , respectivamente. Vea la sección 5.3 del manual si es terriblemente curioso.

Como los compiladores son lo suficientemente inteligentes como para manejar los trucos de optimización de alto nivel integrados en la sintaxis de C, ahora son solo una conveniencia sintáctica.

Python no tiene trucos para transmitir intenciones al ensamblador porque no usa uno.

msw
fuente
44
Javascript tiene ++. No creo que sea un "truco para transmitir intenciones al ensamblador". Además, Python tiene bytecode. Entonces creo que la razón es otra cosa.
Nathan Davis el
13
Este negocio de "proporcionar pistas al compilador" es de hecho un mito. Francamente, es una adición tonta a cualquier idioma y viola los siguientes dos preceptos: 1. No codifica para que la computadora lea, codifica para que otro ingeniero lea. Y 2. No codifica para que lea un ingeniero competente, codifica para que un ingeniero competente lea mientras está exhausto a las 3 am y se sube a la cafeína.
3
@ tgm1024 Para ser justos, al codificar un teletipo semidúplex de 10–30 caracteres por segundo, codifica para poder ingresarlo antes de la próxima semana.
msw
44
@ tgm1024 Unix y C vieron la mayor parte de su desarrollo inicial en PDP-11 que usaban teletipos increíblemente lentos para la comunicación del usuario. Si bien tiene toda la razón de que hoy la codificación de la máquina es en su mayoría tonta, en ese entonces era la interfaz Humano / Máquina la que era el cuello de botella. Es difícil imaginar trabajar tan lentamente si nunca tuvo que hacerlo.
msw
65

Siempre supuse que tenía que ver con esta línea del zen de Python:

Debe haber una, y preferiblemente solo una, forma obvia de hacerlo.

x ++ y x + = 1 hacen exactamente lo mismo, por lo que no hay razón para tener ambos.

GSto
fuente
10
one--es cero?
Andre Holzner
25
one--es uno en la oración, pero cero inmediatamente después. Entonces este 'koan' también sugiere que los operadores de incremento / decremento no son obvios.
Victor K
14
@EralpB Si elimina + =, entonces no puede hacer cosas como x + = 10. + = es un caso más general de ++
Rory
8
Además: "explícito es mejor que implícito".
Ber
2
Definitivamente no es lo mismo, porque x + = 1 NO es una expresión, es una declaración, y no evalúa nada. No puede hacer cosas como: 'row [col ++] = a; fila [col ++] = b '. Sin mencionar las cosas pre-inc y post-inc que tiene c ++.
Uri
38

Por supuesto, podríamos decir "Guido simplemente decidió de esa manera", pero creo que la pregunta es realmente sobre los motivos de esa decisión. Creo que hay varias razones:

  • Mezcla declaraciones y expresiones, lo cual no es una buena práctica. Ver http://norvig.com/python-iaq.html
  • En general, alienta a las personas a escribir código menos legible
  • Complejidad adicional en la implementación del lenguaje, que es innecesaria en Python, como ya se mencionó
EMP
fuente
12
Me alegro de que alguien finalmente haya mencionado el aspecto de declaración vs expresión. En C, la asignación es una expresión y, por lo tanto, el operador ++. En Python, la asignación es una declaración, por lo que si tuviera un ++, probablemente también debería ser una declaración de asignación (e incluso menos útil o necesaria).
Martineau
De acuerdo: si se tratara de declaraciones, entonces, como mínimo, no tendría ningún sentido hablar de la diferencia entre los posoperadores y los preoperadores.
Crowman
17

Porque, en Python, los enteros son inmutables (int's + = en realidad devuelve un objeto diferente).

Además, con ++ / - debe preocuparse por el incremento / decremento previo versus posterior, y solo se necesita presionar una tecla más para escribir x+=1. En otras palabras, evita la posible confusión a expensas de muy poca ganancia.

Nathan Davis
fuente
ints son inmutables en C también. Si no lo cree así, intente que su compilador C genere código para 42++... Algo como esto (modificar una constante literal) era realmente posible en algunos compiladores Fortran antiguos (o eso he leído): todos los usos futuros de ese literal en la ejecución de ese programa realmente tendría un valor diferente. ¡Feliz depuración!
Lutz Prechelt
10
Derecha. 42 es una constante literal . Las constantes son (o al menos deberían ser) inmutables. Eso no significa que las C inten general sean inmutables. Una inten C simplemente designa un lugar en la memoria. Y los bits en ese lugar son muy mutables. Puede, por ejemplo, crear una referencia de an inty cambiar el referente de esa referencia. Este cambio es visible en todas las referencias (incluida la intvariable original ) a ese lugar. Lo mismo no es válido para un objeto entero Python.
Nathan Davis
x + = 1 no termina convirtiéndose en inc mem. Python ejecuta una llamada de función para agregar 1 a una variable; es patética.
PalaDolphin
12

¡Claridad!

Python tiene mucho que ver con la claridad y es probable que ningún programador adivine correctamente el significado a --amenos que haya aprendido un lenguaje que tenga esa construcción.

Python también se trata de evitar construcciones que provocan errores y ++se sabe que los operadores son fuentes ricas de defectos. Estas dos razones son suficientes para no tener esos operadores en Python.

La decisión de que Python use sangría para marcar bloques en lugar de medios sintácticos, como alguna forma de horquillado de inicio / fin o marcado final obligatorio, se basa principalmente en las mismas consideraciones.

Por ejemplo, eche un vistazo a la discusión sobre la introducción de un operador condicional (en C cond ? resultif : resultelse:) en Python en 2005. Lea al menos el primer mensaje y el mensaje de decisión de esa discusión (que tenía varios precursores sobre el mismo tema anteriormente).

Curiosidades: La PEP mencionada con frecuencia en ella es la "Propuesta de extensión de Python" PEP 308 . LC significa comprensión de la lista , GE significa expresión del generador (y no te preocupes si eso te confunde, no son ninguno de los pocos puntos complicados de Python).

Lutz Prechelt
fuente
10

Mi comprensión de por qué Python no tiene ++operador es la siguiente: cuando escriba esto en Python a=b=c=1obtendrá tres variables (etiquetas) que apuntan al mismo objeto (cuyo valor es 1). Puede verificar esto utilizando la función id que devolverá una dirección de memoria de objeto:

In [19]: id(a)
Out[19]: 34019256

In [20]: id(b)
Out[20]: 34019256

In [21]: id(c)
Out[21]: 34019256

Las tres variables (etiquetas) apuntan al mismo objeto. Ahora incremente una de las variables y vea cómo afecta a las direcciones de memoria:

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

Puede ver que la variable aahora apunta a otro objeto como variables by c. Porque lo has usado a = a + 1está explícitamente claro. En otras palabras, asigna completamente otro objeto a la etiqueta a. Imagine que puede escribir a++, sugeriría que no asignó a la variablea objeto nuevo sino que el ratter incrementa el antiguo. Todo esto es en mi humilde opinión para minimizar la confusión. Para una mejor comprensión, vea cómo funcionan las variables de Python:

En Python, ¿por qué una función puede modificar algunos argumentos tal como los percibe la persona que llama, pero no otros?

¿Python es llamada por valor o llamada por referencia? Ninguno.

¿Python pasa por valor o por referencia?

¿Python pasa por referencia o pasa por valor?

Python: ¿Cómo paso una variable por referencia?

Comprender las variables de Python y la administración de memoria

Emulación del comportamiento de paso por valor en python

Llamada de funciones de Python por referencia

Code Like a Pythonista: Idiomatic Python

Wakan Tanka
fuente
9

Fue diseñado de esa manera. Los operadores de incremento y decremento son solo atajos para x = x + 1. Python generalmente ha adoptado una estrategia de diseño que reduce la cantidad de medios alternativos para realizar una operación. La asignación aumentada es lo más parecido a los operadores de incremento / decremento en Python, y ni siquiera se agregaron hasta Python 2.0.

Reed Copsey
fuente
3
Sí compañero, como, usted podría reemplazar return a[i++]con return a[i=i+1].
Luís de Sousa
7

Soy muy nuevo en Python, pero sospecho que la razón se debe al énfasis entre los objetos mutables e inmutables dentro del lenguaje. Ahora, sé que x ++ se puede interpretar fácilmente como x = x + 1, pero PARECE que estás incrementando en el lugar un objeto que podría ser inmutable.

Solo mi conjetura / sentimiento / corazonada.

mkoistinen
fuente
En este aspecto, x++está más cerca de x += 1que x = x + 1, estos dos también hacen una diferencia en los objetos mutables.
glglgl
4

Primero, Python solo está indirectamente influenciado por C; está fuertemente influenciado por ABC , que aparentemente no tiene estos operadores , por lo que tampoco debería ser una gran sorpresa no encontrarlos en Python.

En segundo lugar, como otros han dicho, el incremento y la disminución están respaldados por +=y-= ya.

Tercero, soporte completo para a ++y-- conjunto operador generalmente incluye apoyar tanto el prefijo y versiones de sufijo de ellos. En C y C ++, esto puede conducir a todo tipo de construcciones "encantadoras" que me parecen (en mi opinión) contrarias al espíritu de simplicidad y sencillez que adopta Python.

Por ejemplo, si bien la declaración C while(*t++ = *s++);puede parecer simple y elegante para un programador experimentado, para alguien que la está aprendiendo, es todo menos simple. Agregue una mezcla de incrementos y decrementos de prefijo y postfix, e incluso muchos profesionales tendrán que detenerse y pensar un poco.

fresa
fuente
3

Creo que se deriva del credo de Python que "explícito es mejor que implícito".

Sepheus
fuente
Bueno, no escribes explícitamente las declaraciones "comenzar" y "terminar" en Python, ¿verdad? Aunque estoy de acuerdo con la declaración, creo que hay límites para eso. Si bien podemos discutir sobre esos límites, creo que todos podemos estar de acuerdo en que hay una línea que no es práctico cruzar. Y dado que hay tantas opiniones y justificaciones sobre esa decisión, no creo que haya sido una elección clara. Al menos, no puedo encontrar una fuente, donde se indique explícitamente
Hasan Ammori
3

Esto puede deberse a que @GlennMaynard está analizando el asunto en comparación con otros lenguajes, pero en Python, usted hace las cosas al estilo python. No es una pregunta de "por qué". Está ahí y puedes hacer las cosas con el mismo efecto x+=. En The Zen of Python , se da: "solo debería haber una forma de resolver un problema". Las opciones múltiples son excelentes en el arte (libertad de expresión) pero pésimas en ingeniería.

Nihal Sahu
fuente
2

La ++clase de operadores son expresiones con efectos secundarios. Esto es algo que generalmente no se encuentra en Python.

Por la misma razón, una asignación no es una expresión en Python, evitando así el if (a = f(...)) { /* using a here */ }idioma común .

Por último, sospecho que el operador no es muy coherente con la semántica de referencia de Pythons. Recuerde, Python no tiene variables (o punteros) con la semántica conocida de C / C ++.

Ber
fuente
1
nada impide llamar a una función con un efecto secundario en una comprensión de prueba / expresión / lista: f(a)donde ahay una lista, algún objeto inmutable.
Jean-François Fabre
1

Quizás una mejor pregunta sería preguntar por qué estos operadores existen en C. K&R llama operadores de incremento y decremento 'inusuales' (Sección 2.8 página 46). La Introducción los llama "más concisos y, a menudo, más eficientes". Sospecho que el hecho de que estas operaciones siempre surgen en la manipulación del puntero también ha jugado un papel en su introducción. En Python, probablemente se decidió que no tenía sentido intentar optimizar los incrementos (de hecho, acabo de hacer una prueba en C, y parece que el ensamblado generado por gcc usa addl en lugar de incl en ambos casos) y no hay puntero aritmético; entonces habría sido solo una forma más de hacerlo y sabemos que Python detesta eso.

Ludovico Fischer
fuente
1

como lo entendí para que no pienses que el valor en la memoria ha cambiado. en c cuando haces x ++, el valor de x en la memoria cambia. pero en python todos los números son inmutables, por lo tanto, la dirección que x señaló como todavía tiene x no x + 1. cuando escribe x ++, pensaría que x cambiar lo que realmente sucede es que x referencia se cambia a una ubicación en la memoria donde se almacena x + 1 o recrear esta ubicación si no existe.

rafi wiener
fuente
1
Entonces, ¿qué hace que esto sea ++diferente += 1?
Ber
1

Para completar respuestas ya buenas en esa página:

Supongamos que decidimos hacer esto, prefijo ( ++i) que rompería los operadores unarios + y -.

Hoy, el prefijo por ++o --no hace nada, ya que habilita el operador unario más dos veces (no hace nada) o unario menos dos veces (dos veces: se cancela)

>>> i=12
>>> ++i
12
>>> --i
12

Entonces eso potencialmente rompería esa lógica.

Jean-François Fabre
fuente
1

Otras respuestas han descrito por qué no es necesario para los iteradores, pero a veces es útil cuando se asigna para aumentar una variable en línea, puede lograr el mismo efecto usando tuplas y asignaciones múltiples:

b = ++a se convierte en:

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

y se b = a++convierte en:

a,b = a+1, a

Python 3.8 presenta el :=operador de asignación , lo que nos permite lograr foo(++a)con

foo(a:=a+1)

foo(a++) Sin embargo, todavía es difícil de alcanzar.

JeffUK
fuente
2
: = la asignación es una desgracia
nehem
0

Creo que esto se relaciona con los conceptos de mutabilidad e inmutabilidad de los objetos. 2,3,4,5 son inmutables en python. Consulte la imagen a continuación. 2 ha corregido la identificación hasta este proceso de Python.

ID de constantes y variables

x ++ esencialmente significaría un incremento en el lugar como C. En C, x ++ realiza incrementos en el lugar. Entonces, x = 3, y x ++ incrementaría 3 en la memoria a 4, a diferencia de python donde 3 todavía existirían en la memoria.

Por lo tanto, en Python, no necesita recrear un valor en la memoria. Esto puede conducir a optimizaciones de rendimiento.

Esta es una respuesta basada en la corazonada.

Pikesh Prasoon
fuente
0

Sé que este es un hilo antiguo, pero el caso de uso más común para ++ i no está cubierto, que es la indexación manual de conjuntos cuando no hay índices proporcionados. Esta situación es la razón por la cual Python proporciona enumerate ()

Ejemplo: en cualquier idioma dado, cuando usa una construcción como foreach para iterar sobre un conjunto, por el bien del ejemplo, incluso diremos que es un conjunto desordenado y necesita un índice único para todo para distinguirlos, digamos

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

En casos como este, python proporciona un método de enumeración, p. Ej.

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