¿Por qué usar 'eval' es una mala práctica?
Utilizo la siguiente clase para almacenar fácilmente datos de mis canciones.
class Song:
"""The class to store the details of each song"""
attsToStore=('Name', 'Artist', 'Album', 'Genre', 'Location')
def __init__(self):
for att in self.attsToStore:
exec 'self.%s=None'%(att.lower()) in locals()
def setDetail(self, key, val):
if key in self.attsToStore:
exec 'self.%s=val'%(key.lower()) in locals()
Siento que esto es mucho más extensible que escribir un if/else
bloque. Sin embargo, he oído que eso eval
no es seguro. ¿Lo es? ¿Cual es el riesgo? ¿Cómo puedo resolver el problema subyacente en mi clase (establecer atributos self
dinámicamente) sin incurrir en ese riesgo?
Sí, usarlo eval
es una mala práctica. Sólo por nombrar algunas razones:
- Casi siempre hay una mejor manera de hacerlo.
- Muy peligroso e inseguro.
- Dificulta la depuración
- Lento
En tu caso puedes usar setattr en su lugar:
class Song:
"""The class to store the details of each song"""
attsToStore=('Name', 'Artist', 'Album', 'Genre', 'Location')
def __init__(self):
for att in self.attsToStore:
setattr(self, att.lower(), None)
def setDetail(self, key, val):
if key in self.attsToStore:
setattr(self, key.lower(), val)
Hay algunos casos en los que tienes que usar eval
o exec
. Pero son raros. Usar eval
en su caso es una mala práctica con seguridad. Hago hincapié en las malas prácticas porque eval
y exec
con frecuencia se utilizan en el lugar equivocado.
Respondiendo a los comentarios:
Parece que algunos no están de acuerdo en que eval
el caso OP sea "muy peligroso e inseguro". Esto podría ser cierto para este caso específico, pero no en general. La pregunta era general y las razones que enumeré también son válidas para el caso general.
El uso eval
es débil, no es una mala práctica claramente.
Viola el "Principio Fundamental del Software". Su fuente no es la suma total de lo ejecutable. Además de su fuente, están los argumentos
eval
, que deben entenderse claramente. Por este motivo, es la herramienta de último recurso.Suele ser una señal de diseño irreflexivo. Rara vez hay una buena razón para el código fuente dinámico, creado sobre la marcha. Casi cualquier cosa se puede hacer con delegación y otras técnicas de diseño OO.
Conduce a una compilación sobre la marcha relativamente lenta de pequeños fragmentos de código. Una sobrecarga que se puede evitar utilizando mejores patrones de diseño.
Como nota a pie de página, en manos de sociópatas trastornados, puede que no funcione bien. Sin embargo, cuando nos enfrentamos a usuarios o administradores sociópatas trastornados, es mejor no darles Python interpretado en primer lugar. En manos de los verdaderamente malvados, Python puede ser un riesgo; eval
no aumenta el riesgo en absoluto.