En el libro que estoy leyendo en Python, sigue usando el código eval(input('blah'))
Leí la documentación y la entiendo, pero aún no veo cómo cambia la input()
función.
¿Qué hace? Alguien puede explicar?
En el libro que estoy leyendo en Python, sigue usando el código eval(input('blah'))
Leí la documentación y la entiendo, pero aún no veo cómo cambia la input()
función.
¿Qué hace? Alguien puede explicar?
Respuestas:
La función eval permite que un programa Python ejecute código Python dentro de sí mismo.
Ejemplo de eval (shell interactivo):
>>> x = 1
>>> eval('x + 1')
2
>>> eval('x')
1
eval()
también se puede usar para ejecutar código altamente dinámico, pero debe tener plena conciencia de los riesgos de seguridad y rendimiento antes de usarlo.
eval
, ni podría hacer lo que hace eval
.
eval
, además de ser inseguro, no puede ejecutar programas completos como lo hace el teclado porque solo puede evaluar una sola expresión.
eval()
interpreta una cadena como código. La razón por la que tanta gente le ha advertido sobre el uso de esto es porque un usuario puede usar esto como una opción para ejecutar código en la computadora. Si tiene eval(input())
e os
importó, una persona podría escribir input()
os.system('rm -R *')
y eliminar todos sus archivos en su directorio de inicio. (Suponiendo que tiene un sistema unix). Usar eval()
es un agujero de seguridad. Si necesita convertir cadenas a otros formatos, intente usar cosas que hagan eso, como int()
.
eval
con input()
es un agujero de seguridad. No ponga input()
dentro de una declaración eval y estará bien.
eval
es un problema de seguridad en muchos casos.
input
generalmente toma sus datos de la consola, el usuario podría simplemente salir del programa y escribir de rm -R *
todos modos ...
Muchas buenas respuestas aquí, pero ninguna describe el uso de eval()
en el contexto de its globals
y locals
kwargs, es decir eval(expression, globals=None, locals=None)
(ver documentos eval
aquí ).
Se pueden usar para limitar las funciones que están disponibles a través de la eval
función. Por ejemplo, si carga un nuevo intérprete de Python, el locals()
y globals()
será el mismo y se verá así:
>>>globals()
{'__loader__': <class '_frozen_importlib.BuiltinImporter'>, '__doc__': None,
'__spec__': None, '__builtins__': <module 'builtins' (built-in)>,
'__package__': None, '__name__': '__main__'}
Ciertamente, hay funciones dentro del builtins
módulo que pueden causar un daño significativo a un sistema. Pero es posible bloquear cualquier cosa y todo lo que no queremos disponible. Pongamos un ejemplo. Digamos que queremos construir una lista para representar un dominio de los núcleos disponibles en un sistema. Para mí tengo 8 núcleos, así que querría una lista [1, 8]
.
>>>from os import cpu_count
>>>eval('[1, cpu_count()]')
[1, 8]
Del mismo modo, todo __builtins__
está disponible.
>>>eval('abs(-1)')
1
Okay. Entonces, allí vemos una función que queremos exponer y un ejemplo de un método (de muchos que pueden ser mucho más complejos) que no queremos exponer. Así que bloqueemos todo.
>>>eval('[1, cpu_count()]', {'__builtins__':None}, {})
TypeError: 'NoneType' object is not subscriptable
Hemos bloqueado efectivamente todas las __builtins__
funciones y, como tal, hemos traído un nivel de protección a nuestro sistema. En este punto, podemos comenzar a agregar nuevamente las funciones que queremos exponer.
>>>from os import cpu_count
>>>exposed_methods = {'cpu_count': cpu_count}
>>>eval('cpu_count()', {'__builtins__':None}, exposed_methods)
8
>>>eval('abs(cpu_count())', {'__builtins__':None}, exposed_methods)
TypeError: 'NoneType' object is not subscriptable
Ahora tenemos la cpu_count
función disponible mientras bloqueamos todo lo que no queremos. En mi opinión, esto es súper poderoso y claramente desde el alcance de las otras respuestas, no es una implementación común. Hay numerosos usos para algo como esto y siempre que se maneje correctamente, personalmente creo que se eval
puede usar de manera segura con gran valor.
nótese bien
Otra cosa que es genial acerca de esto kwargs
es que puede comenzar a usar la taquigrafía para su código. Digamos que usa eval como parte de una tubería para ejecutar texto importado. El texto no necesita tener un código exacto, puede seguir algún formato de archivo de plantilla y aún ejecutar lo que desee. Por ejemplo:
>>>from os import cpu_count
>>>eval('[1,cores]', {'__builtins__': None}, {'cores': cpu_count()})
[1, 8]
En Python 2.x input(...)
es equivalente a eval(raw_input(...))
, en Python 3.x raw_input
se renombró input
, lo que sospecho conduce a su confusión (probablemente estaba buscando la documentación input
en Python 2.x). Además, eval(input(...))
funcionaría bien en Python 3.x, pero aumentaría a TypeError
en Python 2.
En este caso eval
se utiliza para obligar a la cadena devuelta de input
una expresión e interpretada. En general, esto se considera una mala práctica.
input
significa lo que raw_input
hizo en 2.x.
Tal vez un ejemplo engañoso de leer una línea e interpretarla.
Prueba eval(input())
y escribe "1+1"
: esto debería imprimirse 2
. Eval evalúa expresiones.
eval()
evalúa la cadena pasada como una expresión de Python y devuelve el resultado. Por ejemplo, eval("1 + 1")
interpreta y ejecuta la expresión "1 + 1"
y devuelve el resultado (2).
Una razón por la que puede confundirse es porque el código que citó implica un nivel de indirección. La llamada a la función interna (entrada) se ejecuta primero para que el usuario vea el mensaje "bla". Imaginemos que responden con "1 + 1" (citas agregadas para mayor claridad, no las escriba al ejecutar su programa), la función de entrada devuelve esa cadena, que luego se pasa a la función externa (eval) que interpreta la cadena y devuelve el resultado (2).
Lea más sobre eval aquí .
eval()
, como su nombre indica, evalúa el argumento pasado.
raw_input()
ahora está input()
en versiones de python 3.x. Entonces, el ejemplo más común para el uso de eval()
es su uso para proporcionar la funcionalidad que input()
proporciona la versión 2.x de python. raw_input devolvió los datos ingresados por el usuario como una cadena, mientras que input evaluó el valor de los datos ingresados y los devolvió.
eval(input("bla bla"))
replica la funcionalidad de input()
in 2.x, es decir, de evaluar los datos ingresados por el usuario.
En resumen: eval()
evalúa los argumentos que se le pasan y, por lo tanto, eval('1 + 1')
devuelve 2.
Una de las aplicaciones útiles de eval()
es evaluar las expresiones de python desde cadenas. Por ejemplo, cargar desde la representación de cadena de archivo del diccionario:
running_params = {"Greeting":"Hello "}
fout = open("params.dat",'w')
fout.write(repr(running_params))
fout.close()
Léalo como una variable y edítelo:
fin = open("params.dat",'r')
diction=eval(fin.read())
diction["Greeting"]+="world"
fin.close()
print diction
Salida:
{'Greeting': 'Hello world'}
eval
hace?
Llego tarde a responder esta pregunta, pero nadie parece dar una respuesta clara a la pregunta.
Si un usuario ingresa un valor numérico, input()
devolverá una cadena.
>>> input('Enter a number: ')
Enter a number: 3
>>> '3'
>>> input('Enter a number: ')
Enter a number: 1+1
'1+1'
Por lo tanto, eval()
evaluará el valor devuelto (o expresión) que es una cadena y devolverá entero / flotante.
>>> eval(input('Enter a number: '))
Enter a number: 1+1
2
>>>
>>> eval(input('Enter a number: '))
Enter a number: 3.14
3.14
Por supuesto, esta es una mala práctica. int()
o float()
debe usarse en lugar de eval()
en este caso.
>>> float(input('Enter a number: '))
Enter a number: 3.14
3.14
Otra opción si desea limitar la cadena de evaluación a literales simples es usar ast.literal_eval()
. Algunos ejemplos:
import ast
# print(ast.literal_eval('')) # SyntaxError: unexpected EOF while parsing
# print(ast.literal_eval('a')) # ValueError: malformed node or string
# print(ast.literal_eval('import os')) # SyntaxError: invalid syntax
# print(ast.literal_eval('1+1')) # 2: but only works due to a quirk in parser
# print(ast.literal_eval('1*1')) # ValueError: malformed node or string
print(ast.literal_eval("{'a':1}")) # {'a':1}
De los documentos :
Evalúe de forma segura un nodo de expresión o una cadena que contenga un literal de Python o una pantalla de contenedor. La cadena o nodo proporcionado solo puede consistir en las siguientes estructuras literales de Python: cadenas, bytes, números, tuplas, listas, dictos, conjuntos, booleanos y Ninguno.
Esto se puede usar para evaluar de forma segura las cadenas que contienen valores de Python de fuentes no confiables sin la necesidad de analizar los valores uno mismo. Es no capaz de evaluar expresiones arbitrariamente complejas, por ejemplo, la participación de los operadores o indexación.
En cuanto a por qué es tan limitado, de la lista de correo :
Permitir expresiones de operador con literales es posible, pero mucho más complejo que la implementación actual. Una implementación simple no es segura: puede inducir el uso básicamente ilimitado de CPU y memoria sin esfuerzo (intente "9 ** 9 ** 9" o "[Ninguno] * 9 ** 9").
En cuanto a la utilidad, esta función es útil para "volver a leer" valores literales y contenedores en cadena por repr (). Esto se puede usar, por ejemplo, para la serialización en un formato similar pero más potente que JSON.
ast.literal_eval
no es compatible con operadores, contrario a su '1+1'
ejemplo. No obstante, admite listas, números, cadenas, etc., por lo que es una buena alternativa para eval
casos de uso comunes .