python - ¿Por qué falla ast.literal_eval(''5*7'')?
abstract-syntax-tree (2)
La pregunta no es "por qué
*
no se acepta" sino más bien "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 cambio consisten en la parte real y la parte imaginaria sumadas juntas;
la parte imaginaria se señala con
j
.
literal_eval
necesita soportar binario
+
y
-
para soportar constantes de números complejos como
1 + 2j
o
-3.4e-5 - 1.72e9j
.
En muchas versiones, incluida Python 3.5,
literal_eval
es mucho más laxo de lo
necesario
: acepta cualquier cadena de sumas y restas mientras los lados izquierdo y derecho evalúen
cualquier
número, por lo tanto
(1 + 3) + 2 + (4 - 5)
todavía 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 pueda 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]
¿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: <_ast.BinOp object at ...>
La documentation no explica esto.
Encontré ese problema después de responder esta pregunta en SO: Obtener el 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, que
5 + 7
funciona es un error, pero que es difícil de solucionar sin romper el soporte para construir números complejos.
La
implementation
limita el uso a operandos que son números, unarios
+
y
-
, u otros operadores binarios (por lo que no puede usarlos para concatenar listas o producir una diferencia establecida).
También vea varias entradas relacionadas con el rastreador de errores de Python: # 25335 ast.literal_eval no puede analizar los números con los principales "+" , # 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 más tarde produce un objeto
complex(5, 2)
partir del resultado, cuando realmente ejecuta la suma.