¿Qué está haciendo este extraño comportamiento del colon?

104

Estoy usando Python 3.6.1 y me he encontrado con algo muy extraño. Tenía un simple error tipográfico en una tarea de diccionario que me tomó mucho tiempo encontrar.

context = {}
context["a"]: 2
print(context)

Salida

{}

¿Qué está context["a"]: 2haciendo el código ? No plantea un SyntaxErrorcuándo debería en mi opinión. Al principio pensé que estaba creando un corte. Sin embargo, al escribir se repr(context["a"]: 2)genera un SyntaxError. También escribí context["a"]: 2en la consola y la consola no imprimió nada. Pensé que tal vez regresó None, pero no estoy tan seguro.

También pensé que podría ser una declaración if de una sola línea, pero esa tampoco debería ser la sintaxis correcta.

Además, context["a"]debería plantear un KeyError.

Estoy perplejo. Que esta pasando?

justengel
fuente
2
Esta pregunta ya tiene un engaño y está bastante claro que esto es confuso para los principiantes de Python. Supongo que esto es peor si Python es su único idioma, donde la sugerencia de tipo y la definición de variable antes de la inicialización en general pueden parecer extrañas. Me imagino que es imposible generar un error ya que este comportamiento es deliberado y, a veces, útil como se explica en PEP 526, y no desea romper la compatibilidad. Sin embargo, me pregunto si los desarrolladores de Python considerarían agregar un mensaje de advertencia útil para algunos casos.
Chris_Rands
1
¿Responde esto a tu pregunta? ¿Qué son las anotaciones de variables en Python 3.6?
Georgy

Respuestas:

98

Ha escrito accidentalmente una anotación de variable sintácticamente correcta . Esa característica se introdujo en Python 3.6 (consulte PEP 526 ).

Aunque una anotación de variable se analiza como parte de una asignación anotada , la declaración de asignación es opcional :

annotated_assignment_stmt ::=  augtarget ":" expression ["=" expression]

Así, en context["a"]: 2

  • context["a"] es el objetivo de la anotación
  • 2 es la anotación en sí
  • context["a"] se deja sin inicializar

El PEP establece que "el destino de la anotación puede ser cualquier destino de asignación único válido, al menos sintácticamente (depende del verificador de tipo qué hacer con esto)" , lo que significa que la clave no necesita existir para ser anotado (por lo tanto, no KeyError). Aquí hay un ejemplo del PEP original:

d = {}
d['a']: int = 0  # Annotates d['a'] with int.
d['b']: int      # Annotates d['b'] with int.

Normalmente, la expresión de anotación debería evaluarse a un tipo de Python; después de todo, el uso principal de las anotaciones es la sugerencia de tipo, pero no se aplica. La anotación puede ser cualquier expresión de Python válida , independientemente del tipo o valor del resultado.

Como puede ver, en este momento las sugerencias de tipo son muy permisivas y rara vez útiles, a menos que tenga un verificador de tipo estático como mypy .

vaultah
fuente
12
=Entonces, ¿no debería requerir un operador de asignación? La clave no existe. Esto me parece mal.
justengel
1
En este caso, : es el operador de asignación. Solo estamos "asignando" una anotación de tipo solo, no una clave. Dudo que haya alguna razón para permitirlo, solo un efecto secundario involuntario de agregar la sintaxis de anotación.
chepner
1
@chepner Parece que esto no es un efecto secundario en mi humilde opinión. Esto es exactamente para lo que se diseñó el PEP correspondiente.
Ma0
6
Sin embargo, es extraño que le permita anotar un objetivo que aún no se ha definido. Si mi primera línea es x: stre inmediatamente seguida de type(x), el intérprete generará un NameError. En mi opinión, la sintaxis debe hacer cumplir el objeto está predefinido o se define en el acto. Esto solo introduce confusión.
r.ook
2
@Idlehands Sin embargo, esto frustra el propósito. Tener x = 'i am a string'antes de x: strhace que el último tipo de redundante .. Esto no debería haber sido añadido en absoluto. Estuvo bien como comentario; Nunca muestro que se usa de una forma u otra.
Ma0