Metaprogramación en Python
Python está bárbaro, es sencillo y todo... siempre leí que era muy fácil hacer metaprogramming con él, pero el problema es que uno haga metaprogramming de una forma fácil en su mente. :-P
Veamos, la función getattr(), disponible en el módulo __builtins__ (o sea, disponible en todo momento), me permite cambiar esto:
def get_transportistas_custodia(id_custodia):(lo malo es que tengo que hacer una función por cada tipo de empresa relacionada con custodia).
""" Devuelvo todos los transportistas que están relacionados con una custodia """
c = Custodia.objects.get(id=1)
# Necesito el conjunto de transportistas de la custodia
return c.transportistacustodia_set.all()
def get_asegurados_custodia(id_custodia):
""" Devuelvo todos los asegurados que están relacionados con una custodia """
...
Por esto:
def get_empresas_relacionadas_custodia(id_custodia, empresa_relacionada='transportista'):Esto es muy bonito. Lo que no había podido hacer hasta ahora era parametrizar con una variable las llamadas a función. Hablo de cosas como esta:
""" Devuelvo todos los objetos de la empresa relacionada que están
relacionados con una custodia.
empresa_relacionada es un string que contiene el tipo de empresa con la cual
relacionar a custodia.
"""
c = Custodia.objects.get(id_custodia)
# Necesito el conjunto de empresas relacionadas de la custodia
return getattr(c, empresa_relacionada + 'custodia_set').all()
def has_empresa_relacionada_custodia(id_custodia, empresa_relacionada='transportista',Acá evidentemente no sabía cómo hacer para "poner" en la llamada a una función el nombre del parámetro que tengo en una variable (empresa_relacionada en este caso). Siempre leí que el "eval is evil" (además de muy lento en su ejecución), pero hasta ahora no podía evitar esto.
id_empresa):
""" Devuelve true si la empresa + id de la empresa especificados están
relacionados con el id_custodia """
c = Custodia.objects.get(id_custodia)
# Necesito el conjunto de empresas relacionadas de la custodia
empresas = getattr(c, empresa_relacionada + 'custodia_set')
resultado = eval('empresas.get(' + empresa_relacionada + ',' + id_empresa + ')')
if resultado:
return True
else:
return False
Jugando hace un rato descubrí que puedo hacer esto!
def has_empresa_relacionada_custodia(id_custodia, empresa_relacionada='transportista',Groso! Al leer que las funciones con keywords son simples llamadas con
id_empresa):
""" Devuelve true si la empresa + id de la empresa especificados están relacionados
con el id_custodia """
c = Custodia.objects.get(id_custodia)
# Necesito el conjunto de empresas relacionadas de la custodia
empresas = getattr(c, empresa_relacionada + 'custodia_set')
# En la siguiente línea está la magia
resultado = empresas.get(**{empresa_relacionada : id_empresa})
if resultado:
return True
else:
return False
diccionarios, me fijé en esta página:
http://docs.python.org/ref/calls.html
Y ví que se puede llamar a funciones con ** o con * también.
Es un avance importante, ahora puedo parametrizar con valores de variables las llamadas a funciones, y sin usar el eval() (no usen eval, siempre tiene que haber una manera de no usarlo).
Saludos
Marcelo
No hay comentarios.:
Publicar un comentario