Más charlas interesantes

martes, 30 de diciembre de 2008
Siguiendo (y terminando) con la línea del post anterior, les comento sobre otras tres muy buenas presentaciones que ví en los últimos días. Varias de ellas son en las Ted Talks, unas conferencias sobre temas diversos que se organizan anualmente bajo el motto "Ideas que vale la pena compartir" (Ideas Worth Spreading). TED cuenta entre sus expositores a personajes como Bono, Richard Branson, Bill Clinton, Frank Gehry, Lawrence Lessig (Creative Commons) y Steven Levitt (Freakonomics).

Jill Bolte Taylor, especialista en neurociencias, despertó una mañana sintiéndose extraña. No le tomó demasiado tiempo reconocer sus síntomas y darse cuenta de que estaba sufriendo un ataque cerebral. Así pudo observar desde adentro mientras todas las funciones de su cerebro iban dejando de funcionar, desde la destreza motora hasta la conciencia de sí misma. Tras los 8 años que le tomó recuperarse completamente de la apoplejía, Jill cuenta paso a paso su experiencia y como cambió su forma de entender el cerebro humano.

Sir Ken Robinson es especialista en creatividad, innovación y recursos humanos. En su charla ¿Las escuelas matan la creatividad? discute el modelo educativo actual y como éste probablemente no esté adaptado para las necesidades del futuro, ya que fue construído a imagen de las necesidades del mundo industrial. Postula con mucho carisma que las escuelas y universidades del futuro deberían incentivar la creatividad por sobre las aptitudes convencionalmente "escolares" como la habilidad de memorizar datos o ejecutar tareas sin errores.

Dan Pinks es el autor del libro "Una mente totalmente nueva" (A Whole New Mind), en el que plantea una idea compatible con la conferencia de Sir Ken Robinson. El subtítulo del libro pregona que las personas predominantemente diestras de cerebro (es decir, aquellas que realizan tareas relacionadas con el hemisferio derecho del cerebro, usualmente tareas creativas) van a ser mucho más valoradas en el futuro, en razón de varios cambios en la dinámica mundial que se están suscitando en este momento. Pinks escribió durante varios años los discursos del candidato presidencial americano Al Gore, así que tampoco le falta cancha para entretener a una audiencia, y discute las ideas generales del libro en una breve conferencia.

Hay un largo listado de de charlas de TED así como de Pop!Tech, suficientes como para perder un verano frente a la pantalla.

Espiral descendente vs. Mundo de posibilidades

lunes, 29 de diciembre de 2008
Hay una historia sobre dos vendedores de zapatos que son enviados a África a evaluar las posibilidades de desarrollo para el mercado de zapatos en el continente negro. El primer vendedor envía el siguiente telegrama: Situación irreparable STOP No usan zapatos. El segundo vendedor en cambio escribió lo siguiente: Magnífica oportunidad STOP Nadie tiene zapatos todavía. Esos mensajes no son descripciones de las circunstancias, sino expresiones de la actitud de los viajeros.
Con esa anécdota comienza Benjamin Zander su charla en Pop!Tech 2008. Zander es director de orquesta en la filarmónica de Boston y profesor de música, así como coach de liderazgo.

A lo largo de la charla, Zander hace subir al escenario a un joven de 15 años con su violonchelo, y mientras le explica en vivo como mejorar su interpretación, hace gala de un carisma y una soltura formidables para expresar su idea central: liderar es esencialmente mostrarle a los demás las posibilidades que están frente a ellos.

Es mi opinión que siempre es un placer ver a una persona hacer algo muy bien, no importa qué sea lo que está haciendo. Benjamin Zander es un maestro de las presentaciones, y como tal, es un placer destinarle media hora a ver una charla que inspira admiración. Su habilidad llega al punto de que Garr Reynolds lo llama el Maestro Zen de las presentaciones. Si lo prefieren, pueden descargar el video (M4V, 335 MB) para verlo en otro momento.

El video está en perfecto y claro inglés.

Python 3: es excepcional

sábado, 27 de diciembre de 2008
El manejo de excepciones en Python 3 recibió también un cambio menor, pero que tiene por objeto evitar una fuente muy común de bugs en el código producidos por el descuido del programador.

Lanzando

En Python 2.x, la sintaxis para lanzar una excepción era usualmente la siguiente:
raise ValueError, "Error de valor!" # o bien
raise ValueError("Error de valor!")
Sin embargo, existe una cantidad de casos diferentes y poco conocidos que se detallan en un largo párrafo del manual de referencia. Está claro que esto es poco deseable, puesto que introduce complicaciones en el lenguaje con el objeto de facilitar usos poco comunes.

Volviendo al caso "usual" citado antes, si bien ambos casos eran equivalentes, se decidió eliminar el primero puesto que la sintaxis resulta un poco confusa. Al leer, no se entiende fácilmente que en realidad el argumento que viene después de la coma en el raise se pasa al constructor de la excepción. Por lo tanto, de ahora en más habrá que restringirse a la segunda opción:
raise ValueError("Error de valor!")
Atajando

Del mismo modo, para atrapar una excepción, se utilizaba el siguiente bloque:
try:
    ... # codigo que lanza una excepción
except ValueError:
    ... # codigo que maneja la excepción
Ahora, si se desea observar el contenido de la excepción para manipularlo de alguna manera, se utiliza el siguiente bloque except:
except ValueError, e:
    print e # "e" referencia la excepción
La dificultad en este caso proviene del uso de la variable e, que puede fácilmente confundirse en el contexto siguiente:
try:
    ... # codigo que lanza una excepción
except (ValueError, TypeError):
    print e
Como se observa, la idea del código es atrapar una excepción de cualquiera de los dos tipos especificados. Sin embargo, muchas veces en las que se desea hacer esto, se termina escribiendo:
except ValueError, TypeError:
    ... # TypeError es ahora una ref. a la excepción!
Está claro que el comportamiento no es el esperado: el bloque citado no atrapa las excepciones de tipo TypeError, sino que únicamente presta atención a los ValueError.

Para evitar esta situación, se introduce a partir de Python 3 una nueva sintaxis que reutiliza el keyword as, ya utilizado antes con las inclusiones de módulos externos para establecer un nombre diferente al módulo importado. La nueva sintaxis se ve así:
except (ValueError, TypeError) as e:
    ... # "e" es lo que uno espera
Gracias a estos cambios se eliminan varias ambiguedades y semánticas complicadas en pos de la simplicidad. Con cambios como estos se hace que el código sea más legible para quienes son nuevos con el lenguaje, y se evitan bugs difíciles de detectar en el manejo de excepciones.

Computer Networks: A systems approach

miércoles, 17 de diciembre de 2008
Este cuatrimestre cursé la materia Teoría de las Comunicaciones ("redes" para los amigos). Dado que acabo de dar el final esta tarde, me parece un buen momento para dejar una breve reseña sobre el libro que sirve de bibliografía principal de la materia. El libro fue escrito por Larry Peterson (profesor de Princeton) y Bruce Davie (fellow de Cisco), y su cuarta y última edición, que es la que tengo entre mis manos, es de 2007.

El otro libro popular de esta asignatura es el de Andrew Tanenbaum, un reconocido autor del área de sistemas del que ya tuve que utilizar varios libros (Sistemas Operativos Modernos, Sistemas Operativos: Diseño e Implementación, y Redes de Computadoras).

El libro de Peterson-Davie es una bocanada de aire fresco después de los de Tanenbaum porque está, lisa y llanamente, muy bien estructurado y muy bien ajustado al espíritu de la carrera de Ciencias de la Computación.

Bien estructurado

El libro está escrito en perfecto inglés técnico. Mis dotes de inglés no son particularmente fantásticas y jamás me tuve que detener a interpretar una expresión u alguna otra. Como es común en los libros de este tema, los capítulos se organizan siguiendo de forma más o menos ajustada las capas del modelo OSI. de abajo hacia arriba.

Sin embargo, lo que hace que este libro sea muy bueno es como construye de forma ascendente todos los tópicos a cubrir, pero de todas maneras se hace posible leerlo por capítulos independientes sin necesidad de volver hacia atrás constantemente. Es difícil explicar el origen de esta cualidad, fuera de un muy buen trabajo de planeamiento y redacción. Sin dudas este libro no solo sirve como introducción a los temas y explicación de los mismos, sino también como material de consulta.

Bien ajustado a Cs. de la Computación

El enfoque sistémico (systems approach) se basa en que el libro contiene una enumeración concisa de como funcionan las cosas, y una discusión tanto o más larga sobre por qué funcionan de esa manera, y cuales son las demás opciones que no tuvieron éxito.

Jamás aparece entre las páginas del libro un bloque interminable de código fuente lleno de punteros que pretende "explicar" como funciona algo. En las únicas oportunidades en que aparece código es para especificar detalles de implementación, y siempre acompañado de un extenso comentario sobre su contenido.

Gracias a esto, el libro da una perspectiva muy útil del funcionamiento de las redes de datos, puesto que explica de forma profunda las particularidades de diseño de algunos protocolos centrales (como TCP), pero además pinta un panorama amplio sobre el resto del abanico. No se trata de un libro que va a quedar obsoleto con la próxima versión de IP.

Lo malo

Sin embargo, hay algunos "defectos" (si pueden llamarlo así) en el libro. Comparado con el Tanenbaum, este libro carece de algo muy interesante: notas de color. Tanenbaum no escatima chistes, reflexiones graciosas y anécdotas con curiosidades sobre los temas abordados. Si bien esto puede parecer decorativo, yo lo encuentro muy interesante y sobre todo, opino que facilita la lectura haciendo más amenos los tramos largos.

El libro de Peterson tiene la cantidad de dos toques creativos:
  • Las citas al principio de cada capítulo, que son excelentes y muy atinadas, a pesar de provenir de ámbitos totalmente disociados con la informática o las redes. Por ejemplo, el capítulo sobre Internet y redes IP comienza con la siguiente cita de Mason Cooley:
    Every seeming equality conceals a hierarchy.
  • Un único chiste en el que, al hacer referencia a que Internet tiene muchos backbones (columnas vertebrales), una nota al pie indica que los autores no conocen ningún otro animal que comparta esta característica.
Sin embargo, el Peterson-Davie tiene muchos recuadros con notas al margen que son muy útiles. Aquí se incluyen discusiones sobre cosas como la utilización de prefijos decimales o binarios para las unidades, o un recuadro especial "Where are they now?", nuevo en la cuarta edición, donde se discute la utilización real del tema que se está discutiendo.

En resumen, una pieza de bibliografía muy recomendada para quiénes como yo, van a estar mayormente usando redes de computadoras, y no diseñándolas o construyéndolas.

Más ingresantes a Ciencias de la Computación

sábado, 13 de diciembre de 2008
Desde 2005 sigo la carrera de Ciencias de la Computación en la Facultad de Ciencias Exactas y Naturales de la Universidad de Buenos Aires (FCEyN - UBA). Si bien la carrera es popular dentro de la facultad, en la medida que fui avanzando en la carrera fui observando como las materias van teniendo una cantidad de alumnos más reducida. Con cierta frecuencia escucho historias de clases con 150 alumnos en materias como Algoritmos 2, que yo calculo habré terminado con unas 50 personas más.

En el Departamento de Computación (departamento responsable de la carrera), la baja en la cantidad de estudiantes empezó a preocupar a varias personas. Esta situación es por demás curiosa dada la buena salida laboral que tiene la carrera, así como la excelente capacitación que da. Durante el último año se lanzó un nuevo sitio web para futuros alumnos. Incluso varios de mis compañeros salen en las fotos de la página :)

Hoy leo en un artículo del diario La Nación que Ciencias de la Computación encabeza la lista de carreras con mayor aumento en la cantidad de inscriptos:
Entre las carreras que más crecieron en candidatos figuran ciencias de la computación (58%), ingeniería civil (47%), ingeniería mecánica (37%) (...)
Sin duda un casi 60% más de inscriptos es una cifra importante.

Python 3: es de colección

miércoles, 10 de diciembre de 2008
Otro de los sets de cambios incluídos en la nueva versión de Python afecta a las colecciones. Entran en esta categoría los diccionarios, conjuntos y secuencias.

Sets y Frozensets son ahora builtin

En Python 3, set es un builtin (ya no es necesario importarlo del módulo sets). Set es una estructura de datos que representa un conjunto de elementos sin un orden específico. La implementación utiliza una tabla de hash, al igual que los diccionarios.

El tipo set es mutable (una misma instancia puede recibir modificaciones), al igual que las listas. Como la listas en Python tienen un equivalente inmutable (las tuplas), los conjuntos lo tienen también en el tipo frozenset. Cabe aclarar que estos tipos ya existían en Python 2.x, pero en Python 3 fueron promovidos a la librería estándar y ya no es necesario importar ningún módulo para utilizarlos.
>>> s = set()          # creo un set vacío
>>> for i in [1,2,3]:
...     s.add(i)
...
>>> 3 in s
True
>>> 4 in s
False
>>> s.remove(2)
>>> s
{1, 3}
>>> fs = frozenset()   # creo un frozenset vacío
>>> fs2 = fs.union(s)  # lo uno con el set {1, 3}
>>> fs2
frozenset({1, 3})      # obtengo un nuevo frozenset
>>> fs
frozenset()            # fs se mantiene intacto
Hay más información en la documentación oficial de set y frozenset.

Nuevos literales y expresiones por comprensión

Set viene acompañado de un literal para su creación: no es necesario construirlo agregando tediosamente elementos a un set vacío como hice arriba. Sin embargo, como la sintaxis es similar a la del literal de diccionarios, hay que tener cuidado al crear uno vacío! El constructor de set vacío es set(), ya que {} está reservado para los diccionarios.
>>> s = {1, 2, 3, 4}           # creo un conjunto
>>> d = {1: 'uno', 2: 'dos'}   # creo un diccionario
>>> s = {}                     # ojo! crea un diccionario
>>> type(s).__name__
'dict'
>>> s = set()
Pero todavía hay más! Python 3 finalmente incorpora diccionarios por comprensión, y ya que estamos en la volada, conjuntos por comprensión. La sintaxis es exactamente la que uno esperaría, muy similar a la de listas por comprensión. Es curioso mencionar que la propuesta de diccionarios por comprensión proviene del PEP 274 (de 2001!). En 2008, Python 3 incorpora esta deseable funcionalidad: se terminaron los días de usar una lista porque es más cómodo!
>>> numeros = [1,2,3,4,5,6,7,8,9,10]
>>> def esPar(x):
...     return x % 2 == 0
...
>>> pares = {x for x in numeros if esPar(x)}
>>> pares
{8, 2, 4, 10, 6}
>>> cuad_impares = {x: x*x for x in numeros if not esPar(x)}
>>> cuad_impares
{1: 1, 3: 9, 9: 81, 5: 25, 7: 49}

Novedades en diccionarios

En primer lugar hay que notar que el método has_key() de diccionarios fue eliminado. Este método era redundante; estas dos expresiones eran equivalentes en Python 2.x, introduciendo una ambigüedad innecesaria:
>>> dicc.has_key('clave')
True
>>> 'clave' in dicc
True
En Python 2.x los métodos keys(), values() y items() de un diccionario devolvían listas contiendo los datos del diccionario (sus claves, sus valores, y los pares clave-valor respectivamente). Asimismo, existían funciones análogas iterkeys, iteritems y itervalues. Estas últimas devolvían iteradores sobre las mismas secuencias que las anteriores.

Python 3 introduce el concepto de vista. Una vista es un objeto intermedio entre el diccionario y los elementos devueltos por los métodos descritos en el párrafo anterior. Los mismos objetos que usábamos en Python 2.x pueden obtenerse ahora a partir de la vista en lugar del diccionario propiamente dicho. Veamos como:
>>> d = {1:'uno', 2:'dos', 3:'tres'}    # armo un diccionario

# Python 2.x
>>> it = d.iterkeys()  # obtengo un iterador sobre las claves
>>> keys = d.keys()    # obtengo una lista de claves
>>> keys
[1, 2, 3]

# Python 3
>>> v = d.keys()    # obtengo la "vista" del diccionario d
>>> type(v).__name__
'dict_keys'
>>> it = iter(v)    # construyo un iterador a partir de la vista (no del dict!)
>>> keys = list(v)  # construyo una lista a partir de la vista
La utilidad de la vista no es aparente aún: sin embargo, la vista introduce una nueva posibilidad. Es claro que la lista obtenida a partir de keys() en Python 2.x está desconectada del diccionario: toda modificación al diccionario posterior a la creación de la lista no se ve reflejada en la misma. Los iteradores se comportan de forma similar: si se modifica el diccionario durante la iteración, se produce una excepción.
>>> d = {1:'uno', 2:'dos', 3:'tres'}
>>> it = d.iterkeys()
>>> del(d[2])
>>> for key in it:
...     print key
... 
Traceback (most recent call last):
RuntimeError: dictionary changed size during iteration
Lo curioso de la vista es que ella también es iterable! (además del iterador que devuelve al aplicarle iter()). Y esta iteración si soporta modificaciones durante su ejecución. De modo que en Python 3, podríamos hacer esto:
>>> v = d.keys()
>>> del(d[2])
>>> for key in v:
...     print(key)
...
1
3
Si obtenemos a partir de la vista el iterador "tipo Python 2.x", tendremos el mismo comportamiento que antes (se emite una excepción al modificar el tamaño del diccionario sobre el que se está iterando).

En resumen, Python 3 incorpora el tipo set a la librería estándar, y notaciones literales y por comprensión tanto para conjuntos como para diccionarios. Estas facilidades hacen más ameno el uso de los tipos de datos correctos para cada tarea, en casos en los que muchas veces se utilizaba una lista por comodidad de notación. Por último, las vistas introducen funcionalidad adicional a los diccionarios, permitiendo modificarlos mientras se los recorre además de mantener las operaciones existentes.

Python 3: diferencias de orden

domingo, 7 de diciembre de 2008
Otro de los cambios introducidos en Python 3 es la abolición del argumento cmp en la operación de ordenamiento de secuencias. Este argumento permitía especificar una función de comparación para utilizar como criterio de ordenamiento, lo cual era bastante cómodo en muchas situaciones. La función debía seguir el modelo de cmp (la builtin).
>>> cmp(1,2)
-1
>>> cmp(2,1)
1
>>> cmp(1,1)
0
Esto se usa mucho para ordenar según el valor de alguna clave particular en el caso de objetos personalizados.
>>> def cmp_edad(p1, p2):
...     return cmp(p1.edad, p2.edad)
... 
>>> class Persona:
...     def __init__(self, nombre, edad):
...             self.nombre = nombre
...             self.edad = edad
...     def __repr__(self):
...             return "%s (%s años)" % (self.nombre, self.edad)
... 
>>> personas = [Persona('Juan', 15), Persona('Lautaro', 3), Persona('Ifigenio', 73)]
>>> personas
[Juan (15 años), Lautaro (3 años), Ifigenio (73 años)]
>>> personas.sort(cmp=cmp_edad)
>>> personas
[Lautaro (3 años), Juan (15 años), Ifigenio (73 años)]
Python 3 elimina esta posibilidad para forzar en cambio la utilización del argumento key. La diferencia es sutil: el valor de key es una función de un único argumento que devuelve una clave que luego se utilizar para ordenar. Esta técnica se llama DSU (por Decorate, Sort, Undecorate) o transformación de Schwartz. Es realmente meritorio lo de este tipo Schwartz, porque logró ponerle su nombre a algo muy simple en 1994, uniéndose a otros personajes avivados similares (como Bolzano!).

La ventaja está en que la implementación con cmp realiza O(n log n) llamadas a la función de comparación, mientras que usando DSU la clave se evalúa una única vez para cada elemento de la secuencia, lo cual es O(n). Si la función de cálculo de la clave es costosa, esto puede hacer una diferencia apreciable en el rendimiento del algoritmo.

Veamos como quedaría el código anterior:
>>> def key_edad(p):
...     return p.edad
... 
>>> personas.sort(key=key_edad)
>>> personas
[Lautaro (3 años), Juan (15 años), Ifigenio (73 años)]
Hay una cuestión más sutil respecto de porqué se decidió eliminar cmp. No solo la función se ejecuta más veces, sino que además el uso corriente utiliza una función anónima (lambda) para hacerlo. Algo del estilo de:
>>> personas.sort(cmp=lambda x,y: cmp(x.edad, y.edad))
Esto tiene el problema añadido de que, si bien la rutina de sorting está implementada en C, la función de comparación no. Esto implica que cada vez que hace falta comparar dos elementos, hay además que hacer un cambio de contexto a Python con el costo adicional que esto representa. El idiom que utiliza key viene con un aditamento: el módulo operator incluye, a partir de 2.4, las funciones attrgetter y itemgetter. Estas funciones, al estar implementadas en C, son mucho más rápidas que sus contrapartidas en Python. Veamos como quedaría lo anterior utilizando la "forma Python 3":
>>> personas.sort(key=operator.attrgetter('edad'))
De esta forma, todo el ciclo de ordenamiento se ejecuta en C y no se repiten cálculos innecesarios, logrando así ordenar de forma muy eficiente. Hay mucha más información sobre ordenamiento de secuencias en Python (pre-3.0) en el wiki oficial.

En resumen, lo que se hizo fue eliminar una forma popular de ordenar secuencias. Las razones son técnicas además de filosóficas: la variante cmp no solo introduce una decisión a la hora de ordenar (¿qué uso? ¿cmp o key?), sino que una de las opciones produce código naturalmente menos eficiente que la otra.

Benchmark

A pedido del público, una comparación entre la alternativa típica de Python 2 usando cmp con lambda contra la versión de Python 3. En el código de prueba ordeno una larga secuencia de objetos en base al valor de su atributo (entero) i. El código que resulta es el siguiente:
class Pepe:
    def __init__(self, i):
        self.i = i

nums = range(1000000)
random.shuffle(nums)
pepos = map(Pepe, nums)

p1 = pepos[:]
p2 = pepos[:]

t = Timer()

# Version cmp
t.start()
p1.sort(lambda x,y: cmp(x.i, y.i))
print "Version lambda: ",
t.stop()

# Version key
t.start()
p2.sort(key=operator.attrgetter('i'))
print "Version key:    ",
t.stop()
La diferencia es abrumadora, no hay más que ver la salida del programa para una secuencia de 1 millón de elementos:
Version lambda:  21.29 segundos
Version key:     3.78 segundos
La versión key es unas 6 veces más rápida. Solo porque es divertido, les dejo un gráfico que compara la performance de los dos métodos (tiempo en segundos vs. cantidad de objetos a ordenar).

Python 3: pequeños cambios misceláneos

sábado, 6 de diciembre de 2008
El operador <>
No existe más, debería usarse != en su lugar (más de una manera de hacer lo mismo!)

El operador !=
Por defecto devolverá lo opuesto de ==, a menos que este último lance NotImplementedError. Este comportamiento es esperable y por tanto su ausencia era una fuente de bugs. En su momento reporté un bug en el ORM de Django por esta precisa razón.

print es una función
Anteriormente, print era un statement: una palabra reservada del lenguaje con tratamiento especial (como es el caso de if o class). En Python 3 print pasa a ser una función convencional. Esto es consistente con el hecho de que no hay ninguna razón para que no lo sea! Si bien va a ser necesario agregar paréntesis que antes no hacían falta, también va a ser posible utilizar print como antes era imposible.
# Python 2.x
print "hola mundo"    # imprime y va a la línea
print "hola mundo",   # imprime y no va a la línea
map(print, [1,2,3,4]) # error!

# Python 3.x
print("hola mundo")
print("hola mundo", end="")
map(print, [1,2,3,4]) # ok!
La mayoría de la sintaxis especial (y muchas veces extraña) de print ahora se reemplaza con keywords para la función. Hay más información en la página de cambios en Python 3 y en la documentación.

La división anda bien
El histórico problema de que la división de enteros da entero en Python se eliminó de una buena vez. Esto era un problema clásico al comenzar a programar, y forzaba a castear a float en muchas ocasiones para asegurarse de que al menos uno de los dos argumentos de la división sea float (en ese caso la división puede devolver float).
uno = 1
dos = 2

# Python 2.x
a = uno / dos
b = uno // dos
c = float(uno) / 2
print a # imprime 1
print b # imprime 1
print c # imprime 0.5

# Python 3.x
a = uno / dos
b = uno // dos
c = float(uno) / 2
print(a) # imprime 0.5 :D
print(b) # imprime 1
print(c) # imprime 0.5
Unificación de Int y Long
En Python 2 existían las dos clases de enteros, y si bien interoperaban entre ellas perfectamente, al imprimir un entero largo por pantalla se imprimía una curiosa L al final.
>>> import sys
>>> sys.maxint
2147483647
>>> sys.maxint + 1
2147483648L # <- "L" al final
>>> type(sys.maxint).__name__
'int'
>>> type(sys.maxint+1).__name__
'long'
Como la constante sys.maxint quedó por lo tanto sin uso, fue eliminada también.

reduce() no es más builtin
En Python 1.0 (allá por 1994) se agregaron varias primitivas de programación funcional: map, filter, reduce. Estas primitivas permiten, usando una única llamada, reescribir varios bucles simples que se suelen utilizar al programar.

Si bien map y filter quedan casi sin cambios en Python 3, reduce se eliminó porque produce código difícil de leer y por lo tanto es más conveniente utilizar un ciclo en lugar de la función. Para los que deseen seguirla utilizando, reduce ahora vive en el módulo functools.

Hace un tiempo expliqué map, filter y reduce en el foro de PC++.

Volaron muchos otros builtins
Todos los siguientes builtins volaron. Los idioms que los reemplazan están disponibles en la documentación sobre cambios en Python 3.
  • apply
  • callable
  • coerce
  • reload
  • file
  • y varios más!

Python 3 está entre nosotros

El 3 de diciembre salió Python 3 (anteriormente llamado Python 3000). Por primera vez en la historia, Python rompe la compatibilidad hacia atrás para mejorar (y en cierta manera, purificar) el lenguaje.
There should be one —and preferably only one— obvious way to do it
"Debería haber una (y preferentemente solo una) manera obvia de hacerlo". Esa cita proviene del Zen de Python, una suerte de poema-chiste-documento que contiene las filosofías detrás del diseño del lenguaje de programación. La que cito arriba, en particular, se contrapone fuertemente con el slogan de Perl: "Hay más de una manera de hacerlo". Los programas en Perl se caracterizan por su muy pobre legibilidad - al punto que a veces se dice que Perl es un lenguaje de solo escritura (una vez que está escrito, nadie podrá leerlo!).

Esa cita es una parte esencial de las modificaciones que sufrió Python en su versión 3. Con el paso de los años, Python fue creciendo y acumulando librerías y funcionalidades. En muchos casos, existían varias maneras de hacer lo mismo sin que quedara claro cual era la mejor. Por esta razón, se eliminaron muchas formas redundantes de hacer cosas, y se aprovechó para corregir algunos detalles que vinieron mal de fábrica. Por supuesto, también hay nuevas funcionalidades.

En el sitio web oficial hay una página detallando todos los cambios en Python 3.

En los próximos días voy a estar comentando algunos de los cambios que se hicieron en Python 3, sus razones de ser, y sus implicaciones en el uso del lenguaje. Python es más simple, consistente (y lindo!) que nunca.

El caso Konabot

martes, 2 de diciembre de 2008
El Konabot es un robot para manipulación de explosivos que se desarrolló en el laboratorio de robótica de la Facultad de Ciencias Exactas y Naturales de la Universidad de Buenos Aires, en un proyecto a cargo del Dr. Juan Santos. Se trata de un proyecto técnicamente avanzado que se hizo a pedido de la brigada de explosivos de los bomberos de la Policía Federal. El robot recibió en 2007 el Premio Innovar en Investigación Aplicada.

Está disponible en YouTube un video explicativo sobre el Konabot.

La polémica

A principios de septiembre de este año se difundió en los pasillos de la facultad que la misma había hecho efectiva la cesión de los derechos de desarrollo del Konabot a la empresa Robots del Sur, creada para tal fin por el inversor Tobías Schmukler (fundador de ITS, una empresa local de servicios informáticos). La transferencia de desarrollos realizados en la universidad pública al sector privado es considerada por muchos parte de la colaboración de la universidad con la sociedad que la sustenta. Sin embargo, los términos de la cesión resultaban curiosos, y más aún las palabras de Schmukler en una entrevista donde comentó las intenciones de su actual empresa Innova Tekné:
La ganancia se da a partir del desarrollo puntual del proyecto y de la venta posterior de esa empresa
A muchos nos chocaron estas ideas, puesto que pareciera que lo se iba a hacer era regalar a Schmukler un desarrollo nacional para que luego un consorcio extranjero lo compre, dejando así al Konabot fuera del alcance de los compradores nacionales y enriqueciendo al inversor.

Desde ya que las opiniones sobre este tema resultaron divididas, pero se armó un gran revuelo en la facultad por esta cuestión. Hay información mucho más completa en el post de PC++ donde comenté esto por primera vez.

Cómo terminó la historia

Hace unos días, llegó de Jorge Aliaga (decano de la facultad) el siguiente mail a la lista de alumnos:
Cuando se informó acerca del convenio, recibimos críticas de diversos sectores, donde se nos acusó de destruir la robótica en el país y las carreras científicas de los miembros en formación del grupo, de regalar las tecnologías generadas con fondos públicos, etcétera. También se atacó públicamente al inversor, tanto dentro como fuera de la Facultad.

Como consecuencia de todos los inconvenientes generados, Robots del Sur ha desistido de sus intenciones de iniciar sus actividades.

Quién esté interesado puede mirar el texto completo del mail, donde el propio decano hace un balance de la situación.

Una reflexión sobre lo ocurrido

¿Fue bueno o malo que el proyecto se echara atrás? ¿Se evitó una estafa a la universidad pública y a los investigadores que trabajaron con esfuerzo, o se evitó el desarrollo de una empresa nacional de tecnología? Sin lugar a dudas esto no está claro, y probablemente nunca se sabrá.

Lo que resulta evidente, al ver los resultados, es que la facultad, desde la incubadora de empresas, manejó muy mal la comunicación con la comunidad universitaria. Desde un punto de vista político operaron pésimamente: de forma casi repentina, varios de los investigadores se desayunaron que su trabajo estaba siendo regalado a un inversor privado, y se produjo una reacción violenta por parte de la comunidad estudiantil, pidiendo explicaciones a los responsables.

¿Qué fue lo que pasó? Yo entiendo que hay tres posibilidades:
  • El proyecto era realmente el manejo extraño que intentaron promover algunas agrupaciones de estudiantes.
  • El proyecto era honesto y bienintencionado, con la mala suerte de que se manejó muy mal la comunicación y el debate sobre la cesión de desarrollos públicos al sector privado, provocando una reacción desfavorable.
  • El proyecto era honesto y bienintencionado, pero se intentó promover por lo bajo, evitando llamar la atención de la comunidad con el objetivo de escapar a una inevitable reacción desfavorable.
Detengámonos sobre la última opción. Es sabido que en la universidad pública, un proyecto de privatización del desarrollo realizado en la facultad será recibido con el ceño fruncido. Es sabido que habrá quien intente sacar partido político oponiéndose a él. Es sabido que boicotear un proyecto polémico, con o sin razón, otorga rédito político a quién impulsa el boicot.

Es en función de esto que resultaría muy comprensible que las autoridades hayan tratado de evitar esta situación para lograr llevar a cabo el proyecto. Hay ahora quienes proclaman el éxito en ponerle freno a las políticas privatistas. Ahora bien, como comunidad, ¿ganamos algo? ¿Si logro martillarme la cabeza, lo puedo considerar un triunfo?