Recomendaciones al programar en Python
Este post fue migrado de un blog hecho con Wordpress. Si se ve mal, dejame un comentario y lo arreglo.
Esta es una traducción de la última sección del PEP 8 de Python, Recomendaciones al programar:
Programming Recommendations
El código debe ser escrito de forma que no tenga desventajas en otras implementaciones de Python aparte de CPython (PyPy, Jython, IronPython, Pyrex, Psyco).
Por ejemplo, no te bases en la implementación eficiente que tiene CPython de concatenación in-place de strings en sentencias de la forma a+=b
o a=a+b
. Esas sentencias corren más despacio en Jython. En su lugar la forma ''.join()
debe ser usada en bibliotecas, en las partes dónde la performance sea importante. Esto asegura que la concatenación ocurra en tiempo lineal en todas las implementaciones.
La comparación con singletons como None
siempre debe hacerse con is
o is not
, nunca con los operadores de igualdad.
También tené cuidado al escribir if x
cuando realmente querés decir if x is not None
, por ejemplo al testear si a una variable o argumento que por defecto es None
le fue asignado a otro valor. El otro valor puede tener un tipo (por ejemplo, un contenedor) que puede ser falso en un contexto booleado! (NdT: por ejemplo [] o {}).
Usá excepciones basadas en clases
Las excepciones basadas en strings en código nuevo deben desaparecer ya que esta característica del lenguaje fue eliminada en Python 2.6.
Los módulos o paquetes deben definir su propia clase base para exepciones específica de su dominio, la cual debe extender la clase built-in Exception
. Siempre incluí un docstring a la clase, por ejemplo:
class MessageError(Exception): """Clase base para errores en el paquete mail."""
La convención para el nombramiento de clases se aplica aquí, aunque deberías agregar el sufijo 'Error' a tus clases de excepciones, si la excepción es un error. Las excepciones que no sean errores no necesitan un sufijo especial.
Al lanzar una excepción, usá raise ValueError('mensaje')
en lugar de raise ValueError, 'message'
.
La forma usando paréntesis es preferida porque cuando los argumentos de la excepción son largos o incluyen formateo de strings, no necesitás usar el carácter de continuación de línea () gracias al paréntesis. La forma vieja será quitada en Python 3000.
Al atrapar excepciones, mencioná la excepción específica cuando puedas, en lugar de usar la clausula except:
.
Por ejemplo, usá:
try: import platform_specific_module except ImportError: platform_specific_module = None
Una clausula except:
atrapará las excepciones SystemExit
y KeyboardInterrupt
, haciendo que sea más difícil interrumpir al programa con Control-C, y puede traer otros problemas. Si querés atrapar todas las excepciones que señalan errores en el programa, usar except Exception:
.
Una buena regla es limitar el uso de la clausula except:
a dos casos:
- Si el manejador de excepción estará imprimiendo o logeando el traceback; al menos el usuario se dará cuenta de que ocurrió un error.
- Si el código necesita hacer algún trabajo de limpieza, pero después deja que la excepción se propague hacia arriba con
raise
.try...finally
es la mejor forma de manejar este caso.
Adicionalmente, para todas las clausulas try/except, limitá la clausula try
a la absolutamente mínima cantidad de código necesario. De nuevo, esto evita esconder bugs.
Si:
try: value = collection[key] except KeyError: return key_not_found(key) else: return handle_value(value)
No:
try: # Too broad! return handle_value(collection[key]) except KeyError: # Will also catch KeyError raised by handle_value() return key_not_found(key)
Usar los métodos de string en lugar del módulo string.
Los métodos de string son siempre más rápidos y comparten la misma API con los strings unicode. Sobreescribí esta regla si necesitás compatibilidad hacia atrás con versiones de Python menores a 2.0.
Usá ''.startswith()
y ''.endswith()
en lugar de rebanamiento de strings (string slicing) para checkear prefijos y sufijos.
startswith()
y endswith()
son más limpios y menos propensos a errores. Por ejemplo:
Si: if foo.startswith('bar'):
No: if foo[:3] == 'bar':
La excepción es sin tu código debe funcionar con Python 1.5.2 (pero esperemos que no!).
La comparación entre tipos de objetos debe usar siempre isinstance() en lugar de comparar tipos directamente.
Si: if isinstance(obj, int):
No: if type(obj) is type(1):
Al chequear si un objeto es un string, recordá que hay strings Unicode también! En Python 2.3, str y unicode tienen una clase base común, basestring, así que podés hacer:
if isinstance(obj, basestring):
En Python 2.2, el módulo types tiene el tipo StringTypes definido para ese propósito, por ejemplo:
from types import StringTypes if isinstance(obj, StringTypes):
En Python 2.0 y 2.1, tenés que hcaer:
from types import StringType, UnicodeType if isinstance(obj, StringType)
o
isinstance(obj, UnicodeType) :
Para secuencias, (strings, listas, tuplas), hacé uso del hecho de que las secuencias vacías tienen valor de verdad falso:
Si:
if not seq: if seq:
No:
if len(seq): if not len(seq):
No escribas strings literales que hagan uso de espacios en blanco al final de una línea. Esos espacios en blanco son visualmente indistingibles y algunos editores (o más recientemente, reindent.py) los eliminan.
No compares valores booleanso con True
o False
usando ==
.
Si:
if greeting:
No:
if greeting == True:
Peor:
if greeting is True:
Comentarios
Comments powered by Disqus