Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
A nivel de mdulo
Aunque from modulo import * es perfectamente vlido a nivel de mdulo, normalmente su uso sigue siendo una mala
idea. En primer lugar porque al utilizarlo perdemos una importante propiedad de Python - y es que puedes saber dnde se define
cada nombre de primer nivel simplemente usando la funcin de bsqueda de tu editor. Adems te arriesgas a encontrarte con
errores en el futuro, si alguno de los mdulos incorpora nuevas funciones o clases.
Una de las preguntas ms horribles con las que te puedes encontrar en los grupos de noticias es por qu el siguiente cdigo no
funciona:
view plaincopy to clipboardprint?
1. f = open("www")
2. f.read()
Por supuesto, funciona perfectamente (asumiendo que tienes un archivo llamado "www"). Pero no funciona si tenemos un from
os import * en algn lugar del mdulo. El mdulo os tiene una funcin llamada open() que devuelve un entero. Aunque
algunas veces pueda resultar de utilidad, sobre escribir las funciones por defecto es uno de los efectos colaterales ms molestos.
Recuerda, nunca ests seguro de los nombres que exporta un mdulo, as que importa slo lo que necesites -- from modulo
import nombre1, nombre2, o manten cada cosa en su mdulo y accede a ellos cuando lo necesites import
modulo;print modulo.nombre.
Cundo es adecuado
Hay situaciones en las que el uso de from modulo import * es adecuado:
En el intrprete interactivo. Por ejemplo el escribir from math import * transforma a Python en una calculadora
cientfica increble.
Al extender un mdulo en C con un mdulo en Python.
Cuando el mdulo especifica que es seguro usar from import *.
>>>
>>>
>>>
>>>
>>>
>>>
>>>
Bien:
>>>
>>>
>>>
>>>
>>>
>>>
>>>
>>>
>>>
>>>
d = {}
for name in sys.argv[1:]:
d[name] = 1
def func(s, **kw):
for var, val in kw.items():
setattr(s, var, val)
d={}
execfile("handle.py", d, d)
handle = d['handle']
handle()
1.
2.
3.
4.
5.
6.
7.
# foo.py
a = 1
# bar.py
from foo import a
if algo():
a = 2 # cuidado: foo.a != a
Bien:
1.
2.
3.
4.
5.
6.
7.
# foo.py
a = 1
# bar.py
import foo
if algo():
foo.a = 2
except:
Python cuenta con una clusula except: que sirve para capturar todas las excepciones. Como todos los errores en Python
producen excepciones, esto provoca que muchos errores de programacin parezcan errores en tiempo de ejecucin, y dificulta el
trabajo de depuracin.
En el siguiente cdigo podemos ver un buen ejemplo:
view plaincopy to clipboardprint?
1. try:
2.
foo = opne("archivo") # "open" esta mal escrito
3. except:
4.
sys.exit("no se pudo abrir el archivo")
La segunda lnea lanza una excepcin de tipo NameError el cual se captura por la clausula except. El programa terminar, y no
tendrs ni idea de que esto no tiene nada que ver con que se pueda o no leer "archivo".
El siguiente ejemplo est mejor escrito
view plaincopy to clipboardprint?
1. try:
2.
foo = opne("archivo") # lo cambiaremos a "open" en cuanto ejecutemos
3. except IOError:
4.
sys.exit("no se pudo abrir el archivo")
Hay algunas situaciones en las que el uso de la clausula except: es adecuado, como en el caso de un framework al ejecutar
retrollamadas, no queremos que ninguna retrollamada moleste al framework.
Excepciones
Las excepciones son una caracterstica muy til de Python. Deberas aprender a lanzarlas cuando ocurra algo inesperado, y
capturarlas slo en los lugares en los que puedas hacer algo por remediarlas.
El siguiente es un anti-modismo muy popular:
view plaincopy to clipboardprint?
1. def get_status(archivo):
2.
if not os.path.exists(archivo):
3.
print "no se encontro el archivo"
4.
sys.exit(1)
5.
return open(archivo).readline()
Supongamos que el archivo se borra justo entre la ejecucin de os.path.exists() y la llamada a open(). Esto hara que la
ltima lnea lanzara una excepcin de tipo IOError. Lo mismo ocurrira si el archivo existiera pero slo tuviera permisos de
lectura. Como al probar la ejecucin del programa no se aprecia ningn error, el resultado de la prueba ser satisfactorio, y se
mandar el cdigo a produccin. Entonces el usuario se encuentra con un IOError que no se ha capturado y tiene que lidiar con
mensajes extraos de trazado de pila.
Aqu tenemos una forma mejor de hacerlo.
view plaincopy to clipboardprint?
1. def get_status(file):
2.
try:
3.
return open(file).readline()
4.
except (IOError, OSError):
5.
print "no se encontro el archivo"
6.
sys.exit(1)
En esta versin hay dos posibilidades, o bien el archivo se abre y se lee la lnea (por lo que funciona incluso en conexiones NFS o
SMB poco fiables), o se muestra el mensaje y se aborta la ejecucin.
Aun as, get_status() asume demasiadas cosas -- que slo se utilizar en un script que no se ejecutar por mucho tiempo y
no, por ejemplo, en un programa que corra durante das en un servidor. Por supuesto al llamar a la funcin se podra hacer algo
como
view plaincopy to clipboardprint?
1. try:
2.
status = get_status(log)
3. except SystemExit:
4.
status = None
asi que intenta usar cuantas menos clausulas except mejor en tu cdigo -- normalmente estas consistirn en un except que
capture todo en main(), o en llamadas internas que siempre deberan ejecutarse con xito.
Por lo tanto la mejor versin sera probablemente
view plaincopy to clipboardprint?
1. def get_status(file):
2.
return open(file).readline()
El cdigo que llama a la funcin puede lidiar con la excecpin si lo necesita (por ejemplo, si prueba la funcin con varios archivos
en un bucle), o simplemente dejar que la excepcin se propague.
La ltima versin tampoco es muy buena -- debido a detalles de implementacin, el archivo no se cerrar cuando se lance una
excepcin hasta que el manejador termine, y puede que no ocurra en alguna implementacin que no se base en C (como por
ejemplo Jython)
view plaincopy to clipboardprint?
1. def get_status(file):
2.
fp = open(file)
3.
try:
4.
return fp.readline()
5.
finally:
6.
fp.close()
1.
2.
3.
4.
# arg!
return dir+"/"+file
# mejor
return os.path.join(dir, file)