[pyar] Pedir perdón o pedir permiso (era: input function)

Facundo Batista facundobatista en gmail.com
Mie Mar 7 13:44:50 ART 2012


2012/3/7 fisa <fisadev en gmail.com>:

> Try/except sirve para capturar excepciones, para manejarlas con
> "gracia", pero capturar una exception es un proceso mucho más caro que
> resolver antes el camino con un if. El try/except debería ser el
> "último recurso" para las cosas que no pudimos evitar por caminos
> normales.

Not really.

Esto que se está discutiendo acá generalmente se llama "pedir perdón o
pedir permiso" (cambié el subject del thread por eso), y ninguno de
los dos es el último recurso de nada.

Hacer un try/except es "pedir perdón" (lo hacés, quizás te equivocás,
pedís perdón con el except). Hacer un if es "pedir permiso", primero
preguntás que onda y luego hacés o no hacés.

¿Dónde o cuando usar uno o el otro? Bueno, depende.

La regla *general* es que si vos estás más o menos seguro que va a ir
todo bien, uses el try/except. Y si no tenés idea, que uses el if. Y
si no te importa, uses el que más lindo queda.

Hay que tener en cuenta que hacer un try/except es muy muy barato si
va todo bien, pero si hay una excepción es caro. Y el if... bueno,
dependerá de cada expresión que se use para ese if.

Sólo como un ejemplo, analicemos el caso del thread anterior.

facundo en phenomenux:~$ timeit.py -s "a = '23'" "int(a)"
1000000 loops, best of 3: 0.972 usec per loop

facundo en phenomenux:~$ timeit.py -s "a = '23'" "
try:
  int(a)
except:
  pass
"
1000000 loops, best of 3: 0.975 usec per loop


O sea, lo mismo. ¿Cuanto cuesta hacer el if?

facundo en phenomenux:~$ timeit.py -s "a = '23'" "a.isdigit()"
10000000 loops, best of 3: 0.165 usec per loop


O sea, un 18% de overhead, si todo va a ir bien.


facundo en phenomenux:~$ timeit.py -s "a = '23a'" "
try:
  int(a)
except:
  pass
"
100000 loops, best of 3: 3.28 usec per loop


O sea, algunas veces más caro si el string era inválido.


Por supuesto, para el caso del ejemplo (tomar input del usuario) estas
diferencias de microsegundos no nos importan.

Pero en otros casos sí, y la velocidad no es lo único a considerar...
saber si algo es un número entero, es fácil, con el isdigit(), y
quizás queda más elegante con el if. Pero si queremos saber si es un
número decimal? Ahí es más complicado, y quizás eso justifique el
poner un try/except alrededor de un float().


Otro caso típico, y repito, es sólo otro ejemplo, es el de usar un
diccionario de caché, ejemplo:

def hace_algo(input):
    try:
        output = dict_como_cache[input]
    except KeyError:
        output = funcion_cara(input)
        dict_como_cache[input] = output
    return output

En ese caso, nosotros esperamos que las cosas estén en el caché, y
está super optimizado para que si está allí, se devuelva el valor
rápido. Y si no está en el caché, el costo de tener la excepción es
despreciable contra el costo de aplicar la función que estamos
cacheando.


Para terminar, recalco que son sólo dos ejemplos, y que hay que
conocer y saber usar ambas "expresiones idiomáticas", y usarlas
donde/cuando corresponde.

Lo que sí, seguro, ninguna de las dos "está mal".

Saludos!

PD: releyendo, veo que quedó como para poner una página en el wiki con esto, no?

-- 
.    Facundo

Blog: http://www.taniquetil.com.ar/plog/
PyAr: http://www.python.org/ar/



More information about the pyar mailing list