January 3, 2009 at 00:12 · Filed under Python
Observemos el siguiente código:
# -*- coding: UTF-8 -*-
def foo(bar=False):
return ‘"bar" vale "%s"’%(bar)
if __name__==‘__main__’:
print (‘Cuando no se especifica el argumento, toma el valor por defecto:\n\tfoo() retorna ‘+foo())
print (‘Cuando sí se especifica el argumento, toma el valor especificado:\n\tfoo(bar=\’baz\’) retorna ‘+foo(bar=‘baz’))
La función foo está definida de manera que recibe un parámetro llamado bar. Tal y como está especificada, si al llamarla no se le pasa ese parámetro, bar tomará el valor por defecto False. Por ejemplo, con la llamada foo(), sin más, bar pasa a ser False, con lo que la función retorna “bar” vale “False”.
Si sí se le pasa ese argumento, la función simplemente usa el valor proporcionado:
>>> import wx_formas
>>> wx_formas.foo(3)
‘"bar" is "3"’
>>> wx_formas.foo(None)
‘"bar" is "None"’
>>> wx_formas.foo([1,2,3])
‘"bar" is "[1, 2, 3]"’
>>>
La ejecución del código original da el siguiente resultado:
Cuando no se especifica el argumento, toma el valor por defecto:
foo() retorna "bar" vale "False"
Cuando sí se especifica el argumento, toma el valor especificado:
foo(bar=‘baz’) retorna "bar" vale "baz"
También se le puede pasar un número variable de argumentos a una función, bien con def foo(*tupla_de_argumentos), o bien con def foo(**diccionario_de_argumentos).
En el libro Learning Python, de Mark Lutz, hay más información acerca de esto (capítulo 16, pág. 331 en la tercera edición, de octubre de 2007 en inglés).
Por darle un poco más de chicha al artículo, diré que acabo de encontrar la Py Zine, revista dedicada enteramente a Python.
December 6, 2008 at 23:53 · Filed under Python
Del libro Learning Python, de Mark Lutz. Ejercicios de la parte VII, acerca de las excepciones en Python.
El ejercicio 1, aunque están resueltos en el propio libro, pongo mi solución por aquí y la comento:
- Enunciado: Escribir una función llamada oops que lanza una excepción IndexError. Después, escribir otra función que llame a oops dentro de una estructura try/except para capturar la excepción. ¿Qué ocurre si oops lanzara la excepción KeyError? ¿De dónde vienen los nombres KeyError e IndexError? (Pista: recuerda que todos los identificadores no calificados vienen de uno de los cuatro ámbitos, según la regla LEGB)
- Mi solución:
def oops
(excepcion
):
raise excepcion
def caller():
try:
oops(KeyError)
except IndexError:
print("Received an IndexError exception")
except KeyError:
print("Received an KeyError exception")
if __name__=="__main__":
caller()
def oops(excepcion):
raise excepcion
Define una función llamada oops que recibe un único argumento referenciado por el identificador excepcion. Notar que no se define de qué tipo debe ser el argumento, si lo que hiciera nuestra función funcionara igual con enteros que con floats no tendríamos que programar dos funciones diferentes, nos valdría con la misma.
En el cuerpo de la función, raise lanza una excepción. De esta manera, se consigue que se deje de ejecutar la función oops nada más hacer el raise, y la función que llamó a ésta reciba la excepción.
def caller():
try:
oops(KeyError)
except IndexError:
print("Received an IndexError exception")
except KeyError:
print("Received an KeyError exception")
Define la función caller, que no recibe argumentos. En esta función hay un bloque try/except. En este tipo de bloques se ejecuta el cuerpo del try, y si durante la ejecución se recibe alguna excepción, se comprueba con los bloques except que haya (al menos uno).
En este caso el primer bloque except comprueba si se recibió la excepción IndexError, en cuyo caso ejecuta la sentencia print() que se ve ahí. El print() va con paréntesis porque es la sintaxis exigida por Python 3000 (recién salido del horno), y soportada por versiones anteriores. Hasta ahora había sido habitual verlo como está pero sin esos paréntesis.
Esta función sencillamente llama a la función oops(), y le pasa como parámetro una excepción KeyError. Esa función lanzará entonces una excepción KeyError, que será recibida por el except KeyError de caller() (dado que la llamada a oops() se hizo dentro del try y que existe un except que captura esa excepción). Finalmente imprimirá el mensaje correspondiente según la excepción capturada.
if __name__=="__main__":
caller()
__name__ es una variable built-in que indica el nombre del módulo que se está ejecutando. Si se trata del programa principal, tiene el valor ‘__main__’. Este código es habitual verlo en módulos, donde suele tener la función de ejecutar una serie de test sobre el propio módulo cuando es ejecutado en vez de cuando es incluido en otro script.
Por otra parte, ya contestando a la última pregunta, KeyError e IndexError son dos identificadores de sendas clases derivadas de la clase Exception. Tanto Exception, como sus derivadas KeyError e IndexError están alojadas en el built-in, es decir, que vienen de por sí en el lenguaje, igual que viene el tipo lista o la función print().
La regla LEGB hace referencia a Local, Enclosing function locals, Global y Built-in. Es decir, que python busca los identificadores de las variables en esos ámbitos, por ese orden: primero en variables locales (los argumentos también son variables locales) dentro de la función, luego en variables locales de funciones dentro de las que está definida la función actual, luego a nivel global, y por último, si no lo encontró en ningún nivel anterior, busca en el built-in.
Así, sí hay una variable global foo y otra local del mismo nombre e una función, al hacerle referencia desde la función, se hará referencia a su variable local, y no a la global.
Nota: la identación de código en WordPress la he hecho con el plugin Code-snippet. Y no es recomendable usar el modo visual con él, ya que se cepilla los espacios/tabulaciones.
November 9, 2008 at 00:42 · Filed under Algoritmia, Estructuras de datos, Linux, Shell scripting
Hoy ha tocado colocar un poco el disco duro, y en estas que me da por mirar cuánto ocupa el directorio
.thunderbird/
donde guardo todo el correo que recibo (desde hace años, incluído spam). 1.8G suman todos los correos. Casi nada, teniendo en cuenta que es texto plano.
Buceando en ese directorio llego al fichero
Inbox
de una de mis cuentas de correo. Todo lo que almacena está en formato mbox, que es lo que habitualmente usan los lectores de correo (o MUAs, Mail User Agent). Los MTAs (Mail Transport Agent) suelen usar el formato Maildir ya que evita el cuello de botella que impone mbox ante la concurrencia.
El caso es que me da por mirar a ver qué tal comprimen los diferentes algoritmos de compresión que tengo en Linux, que son básicamente cuatro: bzip2, LZMA (7zip y versiones nuevas del tar), el tradicional Zip (herramientas zip y gzip) y RAR.
Me he centrado sólo en el ratio de compresión de cada programa, no me he preocupado por cuánto tardan en comprimir, ni cuánto se tarda en listar el contenido de un fichero, o en descomprimir un sólo fichero. De hecho es que no he diferenciado entre formatos que comprimen y archivan a la vez, y los que sólo comprimen (p.ej.
bzip2
). He comprimido un sólo fichero, y era un fichero de texto (en formato
mbox
).
Los resultados para un solo fichero
mbox
de 118M:
Con ¿Libre? me refiero a si yo conozco implementaciones libres del algoritmo tanto para comprimir como para descomprimir.
El LZ77 modificado también se conoce como DEFLATE.
Se concluye lo que más o menos ya habíamos observado a base bajarnos discos:
LZMA
es el que más comprime (y es libre),
RAR
no se queda muy lejos (pero no es libre, aunque es bastante multiplataforma),
bzip2
mejora un poco lo del tradicional
Zip
, pero éstos dos ya van teniendo que jubilarse.
Las únicas ventajas que tienen
zip/gzip/bzip2
son a) que aparentemente tardan menos en comprimir (lógico) y b) que están mucho más difundidos: es difícil encontrar un sistema que no tenga alguno de los tres.
LZMA
en cambio, es más difícil de encontrar.
Update (2009-02-17): Hoy en barrapunto.com han publicado Comparación entre diferentes algoritmos de compresión en Linux . Una noticia que enlaza a tres sitios donde han hecho comparativas similares, pero mucho más extensas:
October 31, 2008 at 21:10 · Filed under Bases de datos, Herramientas CASE
DBDesigner es una herramienta CASE para el modelado de bases de datos relacionales.
Funciona sobre Windows y Linux, que yo haya probado, y dice estar preparada para trabajar mano a mano con MySQL.
Desde luego, en el entorno donde hemos tenido que utilizarlo se ha portado mucho mejor que otras herramientas que probamos –MS Visio, y Dia, aunque Dia tampoco estaba mal, y al tener otro enfoque no es muy comparable.
En Debian no hay paquete de esta aplicación, pero se pueden descargar los binarios o el fuente. Se descomprimen los binarios y se ejecutan, sin más.
La aplicación requiere las Kylixlibs (unas librerías de Borland), que tampoco vienen en Debian,
se pueden descargar,
pablo@golgi:~/DBDesigner$
wget http://prdownloads.sourceforge.net/kylixlibs/kylixlibs3-borqt-3.0-2.tar.gz\?download
descomprimir,
pablo@golgi:~/DBDesigner$
tar -xvzf kylixlibs3-borqt-3.0-2.tar.gz
instalar,
pablo@golgi:~/DBDesigner$
cd kylixlibs3-borqt/
pablo@golgi:~/DBDesigner$
sudo ./install.sh
y copiar a /usr/lib/ para que las use DBDesigner
pablo@golgi:~/DBDesigner$
sudo
cp /usr/lib/kylix3/* /usr/lib/
Una vez ahí tan sólo queda ejecutar el DBDesigner,
pablo@golgi:~/DBDesigner$ ./DBDesigner &
Fuentes:
October 31, 2008 at 20:03 · Filed under Ciencia, Cultura, Libros
Cito de Viva la Ciencia, por Antonio Mingote y José Manuel Sánchez Ron (Editorial Crítica):
Además de sus contribuciones científicas. la Revolución Científica nos dejó una serie de innovaciones, no sólo de ideas, teorías y boservaciones, sino también de comportamientos y mecanismos que resultaron esenciales para el avance científico. Nos estamos refiriendo a las asociaciones profesionales.
Las ideas científicas pueden surgir en ocasiones en escenarios solitarios. [...] Pero, tomada en su conjunto, la actividad científica requiere de instituciones en las que los científicos reciban educación especializada, realicen sus experimentos, intercambien ideas y publiquen sus trabajos. Y fue durante la Revolución Científica cuando se crearon instituciones que sirvieron a estos fines: las primeras sociedades científicas realmente significativas y estables.
En la Europa del siglo XVI proliferaron las universidades. Podemos hablar de ellas, y con razón, como centros de saber. Pero es ésta una denominación un tanto equívoca eran, sobre y por encima de todo, centros de enseñanza, y, de hecho, sus planes de estudios y división en facultades se mantuvieron estáticas durante siglos. Se necesitaba otro tipo de centros para que la ciencia pudiese desarrollarse verdaderamente: las academias y sociedades científicas.
El texto acerca de las Sociedades Científicas sigue, pero creo que es suficiente. Por alguna razón me ha recordado a los hacklabs y medialabs: a los laboratorios de andar por casa donde se pueden desarrollar ideas en colectividad.
« Previous entries ·
Next entries »