martes, 14 de agosto de 2007

Youtube usa Python


En esta página hay un poquito de detalle sobre la arquitectura que utiliza YouTube, que sirve alrededor de 100.000.000 (sí, cien millones) de videos por día.

Adivinen qué? Usa Linux + un Application Server escrito en Python. :-D

Psyco es un "acelerador" de python, digamos que compila "al vuelo" el código que interpreta python y lo convierte a código nativo de la plataforma (como si se hubiera escrito en C, digamos). Si a ellos les da resultados, se podría probar para casos donde se necesite performance.

También me sorprende que usen lighthttpd, que es un webserver "liviano" (traducido: "más liviano que Apache"); en ese caso, quiere decir que está listo para utilizar en producción. :-)

Para más detalles lean la página, está muy interesante.

Saludos
Marcelo

Krita: Mezcla de Colores

Krita es una aplicación para edición fotográfica/bitmaps al estilo Photoshop/Gimp/etc.

El video muestra la implementación de la "mezcla de colores" (yo no entendía qué era hasta que lo ví). Muy bueno, Krita pinta como alternativa a Gimp desde hace rato y ojalá sigan poniéndole pilas los desarrolladores.

Además de eso, calculo que a fines de año (gracias a QT 4.x GPL para todas las plataformas) va a estar disponible para Windows y Mac.







Visto en Barrapunto.

Saludos
Marcelo

sábado, 4 de agosto de 2007

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):
""" 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 """
...
(lo malo es que tengo que hacer una función por cada tipo de empresa relacionada con custodia).

Por esto:
def get_empresas_relacionadas_custodia(id_custodia, empresa_relacionada='transportista'):
""" 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()
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:
def has_empresa_relacionada_custodia(id_custodia, empresa_relacionada='transportista',
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
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.

Jugando hace un rato descubrí que puedo hacer esto!
def has_empresa_relacionada_custodia(id_custodia, empresa_relacionada='transportista',
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
Groso! Al leer que las funciones con keywords son simples llamadas con
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