Archivo

Archive for the ‘Programacion’ Category

Se publicó el resultado de Pyweek

abril 20, 2008 Deja un comentario

Hace una rato, verifico si estaban los resultado de la Pyweek, si queres ver la tabla de clasificaciones visita aquí.

Salimos en sexta posición, Pedro’s Robot Factory fue el juego más votado de la competencia. Los comentarios fueron muy positivos, lo que me llego a mi, desde mis conocidos es que era muy difícil de jugar, al menos al comienzo. La música y los gráficos fueron muy aclamados.

Gracias por ayudar a Pedro 😀

Felicitaciones a todos los equipos Argentinos!.

Anuncios
Categorías:Programacion, pygame, python

Experiencia en Pyweek

abril 6, 2008 3 comentarios

La semana anterior se desarrollo la sexta edición de PyWeek, que es una competencia destinada a desarrollar un juego en 7 días usando Python + Pygame, y muchas ganas :). Es la primera vez que participo en una competencia de este tipo, algunos de los chicos del grupo 10 Roboticists from Santa Fe ya habian participado de la edición anterior, la cual desarrollaron Twisted Zombie.

Lo sorprendente de todo es que en 7 días se escribieron aproximadamente…

[nercof] [~/Proyectos/pyweek6/lib]$ wc -l *.py
...
32911 total
[nercof] [~/Proyectos/pyweek6/lib]$

32911 líneas de código 😮 algo asombroso lo que se puede lograr con este lenguaje.

Aprendí un montón, es muy bueno desarrollar en equipo, porque siempre hay algo que aportar, y algo que te llevas de los demás.
El equipo estaba formado por:

  1. Juanjo Conti, programador
  2. Mariano Galán, programador
  3. César Portela, programador, gráficos
  4. Pedro Pérez, programador
  5. Manuel Kaufmann, programador
  6. yo, programador
  7. Gush Bellino, programador
  8. Maxi Peralta, diseñador gráfico
  9. Pablo Martínez, diseñador gráfico
  10. David Capello, música

Por el momento solo esta la versión para Linux, pero no desespereis si sos usuario de Windows, en breve sale!.

Ahora a esperar los resultados de las clasificaciones. Felicitaciones al equipo, y a todos los equipos argentinos!

Categorías:Programacion, pygame, python

Exepciones en IPython

noviembre 24, 2007 Deja un comentario

Free Image Hosting at www.ImageShack.us ¿Que es ipython? Ipython es un interprete interactivo para python, que ofrece muchas mejoras al lado del interprete interactivo de python -ojo!, no digo que sea mejor, o peor, yo no lo uso mucho 🙂 -, pero es bueno conocer las distintas posibilidades que tenemos, ¿no?. Siguiendo con ipython, es un proyecto de Software Libre con licencia BSD, es multiplataforma, tiene autocompletado con la tecla <tab> y muchas funcionalidades más. Como dijo Humitos: “Tenes una consola dentro del interprete de python”.
Si porque eso no lo mencione, pero podemos navegar por el arbol de directorios como si estuvieramos en el shell.
Instalacion en Debian y sus derivados:

debian:/home/nercof# apt-get install ipython

Manos a la obra: primero explico uno comandos basicos y útiles para mi, y despues lo de Exepciones.
Declaremos algunas variables primero.

In [1]: var = 1

In [2]: enum = 2

In [3]: cadena = 'hola'

In [4]: cadenita = 'txt'

El autocompletado con tab, mustra las coincidencias

In [5]: ca

cadena    cadenita  callable  cat

Podemos listar las variables que tenemos activas en la pila de memoria con el comando “whos”, que no solo las lista sino nos menciona el tipo de dato y el valor que tienen:

In [5]: whos

Variable   Type    Data/Info

----------------------------

cadena     str     hola

cadenita   str     txt

enum       int     2

var        int     1

El anterior es un comando propio de ipython, pertenece a las llamadas funciones “magicas” :p, para poder ver todas, solo hagamos:

In [6]: %lsmagic

Available magic functions:

%Exit  %Pprint  %Quit  %alias  %autocall  %autoindent

%automagic  %bg  %bookmark  %cd  %clear  %color_info

%colors %config  %cpaste  %dhist  %dirs  %ed  %edit

[...]

%lsmagic  %macro  %magic  %p  %page  %pdb

[...]

%who  %who_ls  %whos  %xmodeAutomagic is ON, % prefix NOT needed for magic functions.

Y todos los comandos de consola, por dar un ejemplo:

In [9]: pwd

Out[9]: '/home/nercof'

Ahora a las expciones:

Para trabajar con las expciones hice un pequeño ejemplo, solo cree una lista e imprimo el valor de la misma que se encuentra en el índice que me pasan por parámetro y lo guarde en el archivo ejemplo.py:

class Ejemplo:

    def __init__(self, i):

        self.a = [1,2,3,4]

        print self.a[i]

Ahora desde ipython cargamos ese ejemplo y empesamos a jugar con las exepciones:

In [11]: from ejemplo import Ejemplo

In [12]: Ejemplo(2)

Out[13]:3

Ipython contiene tres formas de distintas de reportar una exepcion, una de ellas es la que el interprete interactivo de python usa.
Modo Context: es la que se muestra por defecto, este modo imprime 5 líneas del contexto del código fuente donde sucedio la exepcion, indicando la linea de código que presenta el conflicto
Con nuestro ejemplo veriamos algo asi:

In [12]: Ejemplo(4)

---------------------------------------------------------

exceptions.IndexError  Traceback (most recent call last)
/home/nercof/Proyectos/blog/
/home/nercof/Proyectos/blog/ejemplo.py in __init__(self, i)

      3

      4 class Ejemplo:

      5     def __init__(self, i):

      6         self.a = [1,2,3,4]

----> 7         print self.a[i]

IndexError: list index out of range

Modo Plain: es similar al reporte del traceback del interprete de python. Para seleccionar este modo recurrimos a una de las funciones mágicas “xmode” y hacemos lo siguiente:

In [14]: xmode Plain

Exception reporting mode: Plain

In [15]: Ejemplo(4)

------------------------------------------------------------

Traceback (most recent call last):

  File "", line 1, in ?

  File "ejemplo.py", line 7, in __init__

    print self.a[i]

IndexError: list index out of range

Modo Verbose: similar al modo “Context” pero adicionando la impresion de las variables actuales visibles con sus respectivos valores al momento de ocurrir la exepcion. Es muy útil, porque podemos ver realmente que tienen cuando “explota” nuestro código, pero es potencialmente lento, si nuestra estructura de datos es muy compleja de computar. Para nuestro ejemple puede andar :), miremos que pasa:

In [17]: Ejemplo(4)

-----------------------------------------------------------

exceptions.IndexError   Traceback (most recent call last)
/home/nercof/Proyectos/blog/
/home/nercof/Proyectos/blog/ejemplo.py in

     __init__(self=<ejemplo.Ejemplo instance>, i=4)

      3

      4 class Ejemplo:

      5     def __init__(self, i):

      6         self.a = [1,2,3,4]

----> 7         print self.a[i]

        self.a = [1, 2, 3, 4]

        i = 4

IndexError: list index out of range

In [18]:

Y con eso concluye la forma en que se muestran, ó reportan las exepciones, esta en cada uno elegir la que mas le guste, como ya lo dije Ipython trae una por defecto, pero si a nosotros nos gusta mas otra, no duden en configurarlo, y es muy simple, solo vallan a la carpeta donde se instalo el programa, usualmente en el home de tu usuario -ojo que esta oculta- y acceden a ella para buscar y editar el archico “ipythonrc”, buscando las siguientes lineas:

[...]
#xmode Plain
xmode Context
#xmode Verbose
[...]

Y descomentan la que mas les guste y comentan “Context” y listo!.

Otra forma que tenemos es interactuar directamente con el debugger de python “pdb”, haciendo lo siguiente:

In [18]: pdb
Automatic pdb calling has been turned ON

In [19]: Ejemplo(4)
---------------------------------------------------------------------------
exceptions.IndexError   Traceback (most recent call last)

/home/nercof/Proyectos/blog/
/home/nercof/Proyectos/blog/ejemplo.py in
        __init__(self=<ejemplo.Ejemplo instance>, i=4)
      3
      4 class Ejemplo:
      5     def __init__(self, i):
      6         self.a = [1,2,3,4]
----> 7         print self.a[i]
        self.a = [1, 2, 3, 4]
        i = 4

IndexError: list index out of range
> /home/nercof/Proyectos/blog/ejemplo.py(7)__init__()
      5     def __init__(self, i):
      6         self.a = [1,2,3,4]
----> 7         print self.a[i]

ipdb> list
      2 # -*- coding: utf-8 -*-
      3
      4 class Ejemplo:
      5     def __init__(self, i):
      6         self.a = [1,2,3,4]
----> 7         print self.a[i]

ipdb>exit

Esto nos deja la accion de interactuar con el debugger directamente. Para ver mas sobre esta herramienta pueden ver aquí, o sino vean este artículo escrito por Humitos Python Debugger

Categorías:linux, Programacion, python

SQLObject: Relaciones one-to-one y one-to-many

noviembre 20, 2007 3 comentarios

Quiero contarles mas o menos de que se trata este tema, hoy estuve es estudiando el Modelo de Entidad Relacion de Ghhp, aplicacion que estamos desarrollando con unos amigos y note que había algunas cosas que no me quedaban del todo claro, es decir, de cómo iba a implementar eso en SQLObject, que es el ORM(Object Relational Manager)que optamos usar.
En particular qué hacer con los atributos de las relaciones y cómo afrontar las relaciones binarias con multiplicidad 1..n y las relaciones trinarias.

Soluciones (ó intento de…) a los cuestionamientos anteriores:

Atributos de las relaciones:
Free Image Hosting at www.ImageShack.us
En el Modelo Relacional, las relaciones al igual que las entidades, pueden poseer atributos. Por ejemplo: para registrar el numero de horas por semana que un empleado trabaja en un proyecto, podemos incluir un atributo hora a la relacion TRABAJA_EN. Hasta ahora todo bien, pero cuando queremos crear las clases para contener esas entidades y la relación, ¿a dónde va a para ese atributo?. Eso depende de la multiplicidad de la relacion con las entidades, si tenemos 1:1 ó 1:n, lo podremos trasladar a uno de los tipos de entidad participante.

  1. 1:1 Lo podemos trasladar a cuelquier entidad a la hora de crear las clases sqlobject
  2. 1:n Solo lo podremos trasladar al tipo de entidad que esta del lado n de la relacón.

Relaciones binarias con multiplicidad 1..n (one-to-many)
Para esto lo que nos provee SQLObject es MultipleJoin. ¿Qué es esto?, simplemente significa que un objeto de la clase del tipo A esta contenido por multiples objetos del tipo B. Por ejemplo:un módulo de python contiene múltiples funciones, pero las funciones solo pertenecen a un solo módulo.
Representemos este concepto en SQLObjet:

>>> class PythonFunction(SQLObject):

...     name = StringCol()

...     modulo_id = ForeignKey('PythonModule')

...

>>> class PythonModule(SQLObject):

...     name = StringCol()

...     functions = MultipleJoin('PythonFunction',

                          joinColumn='module_id')

...

>>> PythonFunction.createTable()

>>> PythonModule.createTable()

>>>

Agregemos objetos

>>> modulo = PythonModule(name='mi_modulo')
>>> funcion_uno = PythonFunction(name='f1()',
                   module_id=modulo.id)
>>> funcion_dos = PythonFunction(name='f2()',
                   module_id=modulo.id)

En los ejemplos anteriores a medida que ibamos creando objetos de la clase “PythonFunction”, le ibamos asignando el id del objeto modulo, para crear el correcto mapeo de la relacion que queremos realizar, y hacemos esto porque la claves foraneas en las bases de datos son establecidas con el id, pero como estamos utilizando SQLObject, podemos pasarle la referencia del objeto mismo,
ya que éste provee un mecanismo que desecha todo lo que no le interesa y toma lo que si.
Muestro con un ejemplo.

>>> funcion_tres = PythonFunction(name='f3()',
                    module_id=modulo)

Relaciones binarias con multiplicidad 1..1 (one-to-one)
En SQLObject para establer este mapeo es muy similar al caso anterior, solo que no llevaría el MultipleJoin
Si fuera el caso que una funcion de python tuviera solo un metodo, lo que tendriamos es algo como:

>>> class PythonFunction(SQLObject):
...    name = StringCol()
...    modulo_id = ForeignKey('PythonModule')
>>> class PythonModule(SQLObject):
...    name = StringCol()
...    function = ForeignKey('PythonFunction')
>>>

Relaciones binarias con multiplicidad m..n (many-to-many)
Esta explicacion se las debo 😛 ya que no lo utilizé todavia. Solo se que el proceso es muy similar a lo que les conte antes, solo que tenemos que usar RelatedJoin

Relaciones trinarias
Estas relaciones al momento de crear las clases para la base de datos se convierte inexorablemente en una clase más, la cual contendrá como atributos las claves foráneas de las entidades que la componen.

A medida que valla avanzando mas, si modiico algo ó simplemente aprendo algunas cosillas mas les cuento.

Categorías:Programacion, python, sqlobject

Recursividad

septiembre 28, 2007 3 comentarios

Siguiendo con el estudio para el parcial de Diseño e Implementación de Estructuras de Datos, vamos a ver la Recursión.
Se dice que un proceso es recursivo si forma parte de sí mismo, es decir, que se define en función de sí mismo. La recursión aparece en la vida diaria, en problemas matemáticos, en estructuras de datos y en muchos otros problemas. Es un proceso extremadamente potente, por lo que hay que saber cuándo y cómo aplicarla.

Un método recursivo es un método que, directa o indirectamente, se hace una llamada a sí mismo

En las aplicaciones prácticas, antes de poner en marcha un proceso recursivo es necesario demostrar que el nivel máximo de recursión (que es es el número de veces que se va a llamar a sí mismo), es no solo finito, sino realmente pequeño. La razón es que necesitaremos una cierta cantidad de memoria para almacenar el estado del proceso cada vez que se abandona temporalmente, debido a una llamada para ejecurtar un proceso de sí mismo. El estado de cálculo en curso hay que almacenarlo para recuperarlo cuando se acabe la nueva ejecución del proceso y haya que reanudar la antigua.
Por esta razón a la existen 4 reglas fundamentales de la recursión, que tenemos que tener en cuenta a la hora de realizar nuestro algoritmo.

  1. Caso Base: se debe tener siempre, al menos un caso base que pueda resolverse sin recursión.
  2. Progreso: cualquiera llamada recursiva debe progresar hacia un caso base.
  3. Puede creerlo: asuma siempre que toda llamada recursiva interna funciona correctamente.
  4. Interes compuesto: nunca duplique el trabajo resolviendo la misma instancia de un problema, en llamadas recursivas separadas.

Tipos de recursión según su complejidad

  1. Resursión lineal: Un método recursivo es lineal, si como máximo tiene una llamada recursiva por rama del condicional, de manera que la cantidad de llamadas recursivas puede calcularse como una función lineal que dependerá de la velocidad con la cual progresa hacia el caso base. Ésta a su vez la subdividimos en:
    1. Resursión por la cola: es cuando la llamada recursiva se hace al final del método, no quedan operaciones pendientes sobre los datos, de manera que no hace falta representar con una pila las variables de cada llamada, y el método recursivo lo podriamos transformar tranquilamente en un bucle iterativo.
    2. Veamos el ejemplo del :Máximo común divisor entre a y b


      def mcd( a, b):
      if( b==0):
      return a
      else:
      return mcd( b, a%b)

    3. Recursión no por la cola: es cuando después de ejecutar todas la llamadas recursivas el método debe realizar una operación pendiente para completar le proceso.
    4. Veamos el ejemplo: Obtener el factorial de un número


      def factorial(n):
      if( n==1):
      return 1
      else:
      return n * factorial(n-1)

      Como vemos luego de ejecutar las llamadas recursivas debemos realizar la operacion “*”.

  2. Recursión no lineal: Un método recursivo es no lineal, si hay más de una llamada recursiva por rama del condicional.
    1. Recursión en cascada: es cuando en cada rama hay mas de una llamada a la función recursiva,su complejidad en término de llamadas recursivas será una función exponencial de la profundidad del árbol de las llamadas.
    2. Veamos el ejemplo: Obtener el n-ésimo valor de la serie de Fibonacci


      def fibonacci(n):
      if( n<=1):
      return 1
      else:
      return fibonacci(n-1) + fibonacci(n-2)

    3. Recursión anidada: es cuando alguna llamada recursiva recibe como parámetro a una llamada recursiva, su complejidad en término de llamadas recursivas resultará mucho más dificil de calcular.
    4. Veamos el ejemplo: Función de Ackermann


      def Ackerman(m, n):
      if (m == 0):
      return n+1
      elif (m > 0 and n == 0):
      return ackermann(m-1, 1)
      elif (m > 0 and n > 0):
      return ackermann(m-1, ackermann(m, n-1))

  3. Recursión mutua: se da cuando dos funciones son recurrentes entre sí.
  4. Veamos el ejemplo: decir si es par o impar el parámetro.


    def impar(n):
    if (n==0):
    return false;
    else
    return par(n-1)

    def par(n):
    if (n==0):
    return true
    else:
    return impar(n-1)

Me parece que los aburrí con tanta teoría :)... Falta solo un poco. Que mas podemos comentar de la Recusión?, como la implementamos?. Existen distintas estrategias, trataré de explicar un poco de cada una:

  1. Divide y vencerás: dijo Napoléon Bonaparte 🙂
    Estos algoritmos constan de dos partes:

    1. Dividir: se resuleven recursivamente problemas más pequeños (exepto los del caso base).
    2. Vencer: la solución al problema original se consigue a partir de las soluciones a los subproblemas.
  2. Estos algoritmos son generalmente muy eficientes y tienen menos llamadas recursivas. Por lo general el Orden de éstos algoritmos es del O(N log N).

  3. Programación dinámica: es la técnica que evita la explosión recursiva guardando respuestas en una tabla. Esta estrategia de Agarra todo lo que puedas es la fuente el nombre de esta clase de algoritmos. Resulta agradable que un problema se pueda resolver usando un algoritmo devorador, ya que entonces el algoritmo se suele acercar bastante a nuestra intuición y además el código producido resulta comprensible. Pero como todo no es color de rosas, no siempre funcionan bien.
    El truco está en guardar las soluciones de los subproblemas en un vector.
  4. Algoritmos de vuelta atrás: usan la recursión para probar sistemáticamente todas las posibilidades

Para terminar un buen ejemplo: ¿Qué es la Recursividad?

Categorías:Programacion, python

Código Abierto ó Código Propietario?

septiembre 28, 2007 Deja un comentario

Si te dan a elegir entre un desarrollo de código propietario y otro de código abierto, elige el segundo, porque se comprobó que tardarás menos, incluso días menos, en hacer bien tu trabajo.
En el software privativo el tiempo medio para resolver el problema en una aplicación es de 6,9 días para los desarrolladores empresariales y 6,7 días para los vendedores de software; el 10% de esos casos necesitan unos 10 días para ser resueltos, indica el estudio.

En cambio los desarrolladores de código abierto El tiempo medio entre que se descubre que existe un problema serio en el software y se resuelve es, en el 36 por ciento de los casos, menor a las ocho horas. Sí, sí. Horas. No días. No semanas.

¿Esto quiere decir que el software de código abierto es mejor?.
No soy quien para contestar ésto, solo doy una humilde opinión. Es mejor si consideramos que su transparencia y disponibilidad permite que los fallos puedan detectarse más rápida y fácilmente. En el proceso, además, no se necesita que sea una persona particular la que lo encuentre y lo notifique, sino que es la comunidad la que apunta las soluciones. Y en el software privativo al ser su código cerrado, solo los que participan de ese proyecto tendrán disponibles los materiales para realizar la búsqueda y no es tan fácil ver u entontrar los errores.

Además, la ventaja de que estos fallos se solucionen antes no repercute sólo a los desarrolladores. Todos los usuarios nos beneficiamos con la rapidez en la respuesta.

Para ver más

Categorías:General, linux, Programacion

Análisis de algoritmos

septiembre 27, 2007 3 comentarios

Imagen alojada en imaXenes.comEstoy leyendo sobre este tema porque la semana que viene tenemos el primer parcial de “Diseño e Implementación de Estructuras de Datos”, y es una de las unidades que comprende el examen, ésta junto a la de Recursión son las más interesantes, y útiles a la hora de llevar a cabo la programación.

En que consta este paradigmático tema?.
Cuando ejecutamos un programa, sobre una cantidad de datos debemos estar seguros de que el programa termina en un tiempo razonable, independientemente de la metodología empleada ( POO, Lógica, Procedural, etc.), y del lenguaje utilizado ( Python, Java, C++, etc.). Para ir decubriendo esto tenemos que en primera instancia conocer qué es un algoritmo.
Un algoritmo es un conjunto de instrucciones claramente especificadas que el ordenador debe seguir para resolver un problema, en un tiempo finito.

El análisis de algoritmos es el proceso que empleamos para determinar la cantidad de recursos (tiempo, espacio, etc.), necesarios para la ejecución de un algoritmo en particular. Siendo el tiempo de ejecución una función del tamaño de entrada, puede ser lineal, cuadrática, cúbica o logarítmica. El valor exacto de esta función dependerá de más factores, tales como la velocidad de la máquina, la calidad del compilador, y en alguno casos la calidad del programa.Lo que nosotros vamos a tratar de medir es el índice de crecimiento de éstas funciones.
De las funciones que mencionamos, la lineal representa el algoritmo más eficiente. Por esta razón trataremos que nuestros algoritmos según sea el caso se comporten como una función lineal.

Incluso los trucos de programación más inteligentes no pueden hacer rápido un algoritmo ineficiente. Por tanto, antes de perder el tiempo intenteando optimizar un código, debemos tratar optimizar el algoritmo.

Hay muchos algoritmos radicalmente diferentes ( en términos de eficiencia), que pueden ser utilizados para resolver distintos problemas. Podemos decir que en primera medida, tratamos de utilizar el algoritmos de fuerza bruta que es el más simple de implementar, pero también el menos eficiente.

Supongamos el siguiente ejemplo:
Dado un vector A con n enteros, hallar el mínimo valor de A
¿Cómo lo resolvemos?.
Opción 1:
def minimo_1(A):
....min = A[0]
....for i in vector:
........if(min < i):
............min = i
....return m

Opción 2:
def minimo_1(A):
....A.sort()
....return A[0]

Cuál es más complejo?, por qué?
Para responder adecuadamente esto tenemos que tener en cuenta los Órdenes de Complejidad, y en particular nosotros vemos Reglas generales para la notación O, ésta notación se puede usar para clasificar las funciones de acuerdo a la tasa de crecimiento. Podemos decir que la opción uno es O(N), “del orden N”, decimos ésto porque en el peor caso el mínimo valor se encontrará en el último lugar.
Ahora se preguntarán que si el arreglo A, crece en gran tamaño, nos convendría hacer que nuestro algorítmo se comporte en vez de linealmente, logarítmicamente. Yo les diría que si, pero en éste ejemplo en particular el arreglo – en principio viene desordenado- y por eso una Búsqueda Binaria ó Dicotómica no nos serviria. Tendríamos que estudiar si nos conviene ordenar y buscar ó simplemente buscar linealmente. Pero el mejor comportamiento para ordenar (si no se aprovecha la estructura de las claves) es O(n log n). Los algoritmos más simples son cuadráticos, es decir O(n²). Los algoritmos que aprovechan la estructura de las claves de ordenamiento (p. ej. bucket sort) pueden ordenar en O(kn) donde k es el tamaño del espacio de claves. Como dicho tamaño es conocido a priori, se puede decir que estos algoritmos tienen un desempeño lineal, es decir O(n).
Que es lo que opinan?.

La regla más importante es:
“El tiempo de ejecucion de un bucle es como mucho el tiempo de ejecución de las instrucciones dentro del bucle (incluyendo los test) multiplicado por el número de iteraciones”

Una vez que hemos efectuado el análisis de un algoritmo, queremos ver si es correcto y tan bueno como sea posible. Una forma de hacerlo es implementar el programa y ver si el tiempo de ejecución observado empíricamente se ajusta con el tiempo de predicho por el análisis.

Para terminar mi resumen, quiero aclarar que esto es una herramienta más, es muy efectiva, pero es importante conocer sus limitaciones. No es apropiado para pequeñas cantidades de datos, para ésto utilizamos el algoritmo más simple.

Es un tema que presta a la discución, sanamente no?. Pero se pueden debatir distintas metodologías para implementar sobre un mismo problema.

Referencias:
Análisis de Algoritmos
Tutorial
Algoritmos de Ordenamientos

Categorías:Java, Programacion, python