¿Por qué la asignación de Python no devuelve un valor?
¿Por qué la asignación de Python es una declaración en lugar de una expresión? Si fuera una expresión que devuelve el valor del lado derecho de la asignación, habría permitido un código mucho menos detallado en algunos casos. ¿Hay algún problema que no puedo ver?
Por ejemplo:
# lst is some sequence
# X is come class
x = X()
lst.append(x)
podría haberse reescrito como:
lst.append(x = X())
Bueno, para ser precisos, lo anterior no funcionará porque x
sería tratado como un argumento de palabra clave. Pero otro par de pares (u otro símbolo para argumentos de palabras clave) habría resuelto eso.
Hay muchos que sienten que tener asignaciones como expresiones, especialmente en lenguajes como Python donde se permite cualquier valor en una condición (no solo valores de algún tipo booleano), es propenso a errores. Es de suponer que Guido está/estaba entre los que se sienten así. El error clásico es:
if x = y: # oops! meant to say ==
La situación también es un poco más complicada en Python que en un lenguaje como C, ya que en Python la primera asignación a una variable es también su declaración. Por ejemplo:
def f():
print x
def g():
x = h()
print x
En estas dos funciones las " print x
" líneas hacen cosas diferentes: una se refiere a la variable global x
y la otra a la variable local x
. El x
in g
es local por la cesión. Esto podría ser aún más confuso (de lo que ya es) si fuera posible enterrar la tarea dentro de alguna expresión/declaración más grande.
Las (sub)expresiones de asignación (x := y)
son compatibles desde Python 3.8 (lanzado en octubre de 2019), por lo que ahora puedes reescribir tu ejemplo como lst.append(x := X())
.
La propuesta, PEP 572 , fue aceptada formalmente por Guido en julio de 2018. También hubo propuestas anteriores para expresiones de asignación, como la PEP 379 retirada .
Recordemos que hasta la versión 3, print
también era una afirmación más que una expresión.
La declaración x = y = z
para asignar el mismo valor a múltiples objetivos (o más bien, a múltiples listas de objetivos , ya que también se permite desempaquetar) ya era compatible (por ejemplo, desde la versión 1), pero se implementa como una sintaxis especial en lugar de encadenar subexpresiones de asignación sucesivas. . De hecho, el orden en el que se realizan las asignaciones individuales se invierte: las morsas anidadas (x := (y := z))
deben asignar a y
before x
, mientras que x = y = z
las asignaciones a x
before y
(lo cual puede ser pertinente si configura/asigna los subíndices o atributos de una clase que se ha sobrecargado para crear algunas efecto secundario).
La respuesta del mundo real: no es necesario.
La mayoría de los casos que ve esto en C se deben al hecho de que el manejo de errores se realiza manualmente:
if((fd = open("file", O_RDONLY)) == -1)
{
// error handling
}
Lo mismo ocurre con la forma en que se escriben muchos bucles:
while(i++ < 10)
;
Estos casos comunes se resuelven de manera diferente en Python. El manejo de errores suele utilizar el manejo de excepciones; Los bucles suelen utilizar iteradores.
Los argumentos en contra no son necesariamente trascendentales, pero se sopesan con el hecho de que simplemente no es tan importante en Python.