2012-02-21 15 views
161

En el libro que estoy leyendo en Python, se mantiene utilizando el código eval(input('blah'))¿Qué hace la evaluación de Python()?

leí la documentación, y lo entiendo, pero todavía no ver cómo cambia la función input().

¿Qué hace? ¿Alguien puede explicar?

+41

¿Es eso un libro de Python 3.x un 2.x uno? De cualquier manera, tal uso liberal de 'eval' sugiere que es un libro horrible. – delnan

+10

erm, solo me pregunto ... ¿por qué esto fue aprobado? No me quejo, solo quiero mejorar mis preguntas. – Billjk

+5

Tu libro suena terrible. Debería encontrar un mejor libro, tal vez http://www.greenteapress.com/thinkpython/html/index.html –

Respuesta

164

La función eval permite que un programa python ejecute código python dentro de sí mismo.

ejemplo eval (shell interactivo):

>>> x = 1 
>>> eval('x + 1') 
2 
>>> eval('x') 
1 
+13

jaja, ese era un ejemplo trivial, pero podrías dejar que el usuario escriba un comando arbitrario y que python lo ejecute. De modo que podría hacer que el usuario escriba una cadena de comando y que Python la ejecute como código. Entonces, por ejemplo: eval ("__ import __ ('os'). Remove ('file')"). – BYS2

+44

Parecerá inútil hasta que lo encuentre necesario. Se usa en sitios como codepad.org para permitirle ejecutar scripts en un entorno de prueba. 'eval()' también se puede usar para ejecutar código altamente dinámico, pero debe estar completamente consciente de los riesgos de seguridad y rendimiento antes de usarlo. –

+1

ohhhhhh lo entiendo! gracias – Billjk

24

En Python 2.x input(...) es equivalente a eval(raw_input(...)), en Python 3.x raw_input pasó a denominarse input, que sospecho que conducen a su confusión (que fueron probablemente mirando la documentación para input en Python 2.x). Además, eval(input(...)) funcionaría bien en Python 3.x, pero elevaría un TypeError en Python 2.

En este caso eval se utiliza para obligar a la cadena devuelta desde input en una expresión e interpretado. En general, esto se considera una mala práctica.

+0

O es un libro de Python 3.x, donde 'entrada 'significa lo que' raw_input' hizo en 2.x. – dan04

+1

Sí, eso se me ocurrió después de que escribí mi respuesta inicial, y ese es claramente el caso. – zeekay

4

Quizás un ejemplo engañoso de leer una línea e interpretarla.

Pruebe eval(input()) y escriba "1+1" - esto debería imprimir 2. Eval evalúa expresiones.

+0

¿Por qué debería escribirlo entre comillas? La entrada es obtener una cadena y pasarla a eval, no ejecutar el código, entonces estaría bien si simplemente escribiera 1 + 1 ... ¿? –

+0

El problema es que estás mezclando P2.xy 3.x. En Python 2 su código funciona, pero no tiene sentido evaluarlo dos veces. En python 3 no, y devuelve una cadena. –

5

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 podría estar confundido es porque el código que citó implica un nivel de indirección. La llamada de función interna (entrada) se ejecuta primero para que el usuario vea el aviso "blah". Imaginemos que responden con "1 + 1" (las comillas se añaden 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).

Más información sobre eval here.

99

eval() interpreta una cadena como código. La razón por la cual muchas personas lo han 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()) y os importados, una persona puede escribir en input()os.system('rm -R *') que eliminará todos sus archivos en su directorio personal. (Suponiendo que tienes un sistema Unix). Usar eval() es un agujero de seguridad. Si necesita convertir cadenas a otros formatos, intente utilizar cosas que lo hagan, como int().

+11

Quiere decir usar 'eval' con' input() 'es un agujero de seguridad. No pongas 'input()' dentro de una declaración de evaluación y estarás bien. – Rohmer

+6

@Rohmer, los datos inseguros pueden venir de todas partes: solicitudes web, campos de entrada de formularios, lecturas de archivos, ... no solo desde la entrada de la consola. Incluso si escribe los archivos usted mismo, aún puede contener datos que originalmente provenían de una fuente no confiable. Por lo tanto 'eval' es un problema de seguridad en muchos casos. – sanderd17

3

Una de las aplicaciones útiles de eval() es evaluar las expresiones python de la cadena.Por ejemplo la carga de la representación de cadena archivo de diccionario:

running_params = {"Greeting":"Hello "} 

fout = open("params.dat",'w') 

fout.write(repr(running_params)) 

fout.close() 

leyó en voz como una variable y editarlo:

fin = open("params.dat",'r') 

diction=eval(fin.read()) 

diction["Greeting"]+="world" 

fin.close() 

print diction 

Salida:

{ 'saludo': 'Hola mundo'}

+3

¿Cómo responde esto la pregunta que pregunta qué hace 'eval'? –

4

eval(), como su nombre indica, evalúa el argumento pasado.

input() ahora es raw_input() en las versiones python 3.x. Por lo tanto, el ejemplo más común encontrado para el uso de eval() es su uso para proporcionar la funcionalidad que input() proporciona en la versión 2.x de python. raw_input devolvió los datos ingresados ​​por el usuario como una cadena, mientras que la entrada evaluó el valor de los datos ingresados ​​y los devolvió.

eval(input("bla bla")) duplica así la funcionalidad de input() en 2.x, es decir, de la evaluación de los datos ingresados ​​por el usuario.

En resumen: eval() evalúa los argumentos que se pasan a la misma y, por tanto, eval ('1 + 1') volvió 2.

4

La porción de buenas respuestas aquí, pero ninguno describen el uso de eval en el contexto de es globals= y locals= kwargs. Estos pueden usarse para limitar los métodos que están disponibles a través del método eval. Por ejemplo si se carga un intérprete de python fresca del locals()globals() y será el mismo y ser algo como esto:

>>> globals() 
{'__loader__': <class '_frozen_importlib.BuiltinImporter'>, '__doc__': None, 
'__spec__': None, '__builtins__': <module 'builtins' (built-in)>, 
'__package__': None, '__name__': '__main__'} 

sin duda hay métodos dentro del módulo de builtins que puede hacer un daño significativo a un sistema. Pero es posible bloquear todo y todo lo que no queremos disponible. Tomemos 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 me gustaría una lista [1, 8].

>>>from os import cpu_count() 
>>>eval('[1, cpu_count()']) 
[1, 8] 

Del mismo modo todos __builtins__ está disponible.

>>>eval('abs(-1)') 
1 

Ok. Entonces, vemos un método que queremos exponer y un ejemplo de uno (de muchos que pueden ser mucho más insidiosos) método que no queremos exponer. Entonces bloqueemos todo.

>>>eval('[1, cpu_count()]', {'__builtins__':None}, {}) 
TypeError: 'NoneType' object is not subscriptable 

Hemos bloqueado en la práctica todos los métodos __builtins__ y como tal traído un nivel de protección en nuestro sistema. En este punto, podemos comenzar a agregar nuevamente en los métodos que queremos expuestos.

>>>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 el método cpu_count disponible y seguimos bloqueando 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. Existen numerosos usos para algo como esto y siempre que se maneje correctamente, personalmente creo que el eval se puede usar de forma segura con un gran valor.

N.B.

Algo más que es genial acerca de estos kwargs es que puede comenzar a usar la abreviatura de su código. Supongamos que usa eval como parte de una canalización para ejecutar algún texto importado. El texto no necesita tener un código exacto, puede seguir un formato de archivo de plantilla y aún ejecutar cualquier cosa que desee. Por ejemplo:

>>>from os import cpu_count 
>>>eval('[1,cores]', {'__builtins__': None}, {'cores': cpu_count()}) 
[1, 8] 
Cuestiones relacionadas