[Python-es] Pythoniano y c niano

lasizoillo lasizoillo en gmail.com
Mie Dic 26 11:47:12 CET 2012


El día 26 de diciembre de 2012 11:04, kausdiv <kausdiv en gmail.com> escribió:
> Hola.
> Estoy aprendiendo Python (me gusta muchisimo).
> El problema que todo lo que escribo lo hago al estilo ceniano.  Es decir
> tipo C o java, y quiero adentrarme al estilo pythoniano.
> Por ejemplo este programita que busca los números primos entre 2 números
> dados.
> -------------------------------
> def fprimos(n,x):
>     l=[]
>     for i in range(n,x):
>         isprime=1
>         for k in range(2,i):
>             if i % k ==0 and i<>k:
>                 isprime=0
>                 break
>         if isprime==1:
>             l.append(i)
>     return l
>
> def main():
>     ok=1
>     while ok==1:
>         print " imprime numeros primos desde hasta."
>         print " 0 = Salir "
>         n1=raw_input("Valor inicial ")
>         n2=raw_input("Valor Final ")
>         n1=int(n1)
>         n2=int(n2)
>         if n1==0 or n2==0:
>             ok=0
>         else:
>             print fprimos(n1,n2)
>
> main()
>
> ---------------------------------------
> ¿ como sería el mismo programa pasado a estilo python ?
>


La verdad es que más que con el estilo voy a "quejarme" de otras
características del programa.

Para empezar, tu función para sacar los numeros primos entre dos
números hace lo siguiente:

def fprimos(n1, n2):
    """
    Retorna los numeros primos entre los numeros n1 y n2
    Esto se puede documentar mejor ;-)
    """
    return [n for n in range(n1, n2) if is_prime(n)]

y luego defines la función de si es primo o no dentro del bucle.
Separándolo obtienes poder reutilizar la función de comprobación de
primalidad y reduces la complejidad del programa: cada pieza se
entiende por sí sola.

Para ver si es primo puedes ver código en rosetta code:
http://rosettacode.org/wiki/Primality_by_trial_division#Python

Como ves no es necesario probar todos los divisores desde 2 hasta el
número a probar. Si n tiene un divisor d, también tendrá un divisor D.
d * D = n => si d < D -> d*d <= n. Vamos, que basta comprobar los
divisores hasta la raiz cuadrada del número a comprobar, que quita
muchas pruebas.

En el código de rosetta usa any para evitar la sentencia for con un
break cuando una de las condiciones se cumple. No se si es bueno o no
hacer este tipo de código. Por un lado es conciso y eficiente, pero
por otro a algunos programadores les puede costar más leerlo. Piensa
en quién va a leer el código antes de escribirlo con un estilo u otro
;-)

Otra ventaja de separar el código en dos funciones es que si vas a
ejecutar la función muchas veces con intervalos solapados es posible
que te sea sencillo cachear alguno de los tests de primalidad de forma
sencilla:
http://docs.python.org/3.4/library/functools.html#functools.lru_cache

Pero no siempre los patrones de ejecución de tu código te van a
permitir esto. Eso si, cuando lo permiten es pythonico hacerlo ;-)

Un saludo y espero haberte sido de ayuda,

Javi


Más información sobre la lista de distribución Python-es