¿Por qué falla ast.literal_eval (‘5 * 7’)?

¿Por qué falla la evaluación literal de 5 * 7 , mientras que 5 + 7 no?

 import ast print(ast.literal_eval('5 + 7')) # -> 12 print(ast.literal_eval('5 * 7')) # -> Traceback (most recent call last): ... ValueError: malformed node or string:  

La documentación no explica esto.

Encontré ese problema después de responder esta pregunta en SO: Obtención del resultado de una cadena .

ast.literal_eval() acepta + en los datos evaluados porque 5+2j (número complejo * ) son literales válidos. Lo mismo se aplica a - . Para mantener el código simple, no se intenta excluir + o - como operadores binarios.

No se permiten otros operadores; se supone que la función solo acepta literales, no expresiones.

En otras palabras, ese 5 + 7 funciona es un error, pero es difícil de solucionar sin romper el soporte para construir números complejos. La implementación limita el uso de operandos que son números, operadores unarios + y - u otros operadores binarios (por lo que no puede usarlos para concatenar listas o generar una diferencia establecida).

También vea varias entradas relacionadas con el controlador de errores de Python: # 25335 ast.literal_eval no puede analizar los números con el signo “+” , # 22525 ast.literal_eval () no hace lo que dice la documentación y # 4907 ast.literal_eval no maneja adecuadamente los números complejos


* Técnicamente hablando, 2j es un literal válido; Python analiza 5+2j como int(5) binop(+) complex(0, 2) , y solo posteriormente produce un objeto complex(5, 2) partir del resultado, cuando se ejecuta la adición.

La pregunta no es “por qué * no se acepta”, sino “por qué se acepta + en absoluto”.

ast.literal_eval puede analizar literales, pero no expresiones. Sin embargo, en Python, los números complejos no se expresan como un solo valor literal; en su lugar, consisten en la parte real y la parte imaginaria sumdas; La parte imaginaria se señala con j . así, literal_eval debe admitir binario + y - para admitir constantes numéricas complejas como 1 + 2j o -3.4e-5 - 1.72e9j .

En muchas versiones, incluyendo Python 3.5, literal_eval es mucho más laxo de lo que debe ser: acepta cualquier cadena de sums y restas mientras los lados izquierdo y derecho se evalúen en cualquier número, por lo que (1 + 3) + 2 + (4 - 5) aún se analiza, incluso si no es una constante compleja que consiste en una parte real + imaginaria.


+ y - no se aceptan incondicionalmente: si intenta agregar 2 listas juntas, fallará, aunque puede analizar literales de lista, y la adición se define para las listas:

 >>> ast.literal_eval('[1] + [2]') Traceback (most recent call last): ... ValueError: malformed node or string: <_ast.BinOp object at 0x7fdddbe785f8> >>> ast.literal_eval('[1, 2]') [1, 2] >>> [1] + [2] [1, 2]