1 2 |
# Correcto: if foo is not None: |
1 2 |
# Incorrecto: if not foo is None: |
Para minimizar el esfuerzo involucrado, el decorador functools.total_ordering() proporciona una herramienta para generar los métodos de comparación que faltan.
PEP 207 indica que las reglas de reflexividad son asumidas por Python. Por lo tanto, el intérprete puede intercambiar y > x con x < y, y > = x con x <= y, y puede intercambiar los argumentos de x == y y x! = y. Las operaciones sort() y min() garantizan usar el operador < y la función max() usa el operador >. Sin embargo, es mejor implementar las seis operaciones para que no surja confusión en otros contextos.
1 2 |
# Correcto: def f(x): return 2*x |
1 2 |
# Incorrecto: f = lambda x: 2*x |
La primera manera indica que el nombre del objeto de función resultante es específicamente 'f' en lugar del genérico '<lambda>'. Esto es más útil para trazar el comportamiento de la función y representaciones en cadenas en general. El uso de la asignación por sentencia elimina el único beneficio que puede ofrecer una expresión lambda ante una sentencia def (por ejemplo, que puede integrarse dentro de una expresión más grande).
Diseñe las jerarquías de excepciones basadas en las distinciones donde las excepciones sean necesarias, y no en lugar desde donde se lanzan. Intente responder la pregunta "¿Qué salió mal?" mediante programación, en lugar de solo indicar que "se produjo un problema".
Las convenciones de nombramiento de clases se aplican aquí, aunque debe agregar el sufijo "Error" a sus clases de excepción si la excepción es un error. Las excepciones que no correspondan a un error, deben ser utilizadas para un flujo de control no local u otro tipo de señalización, estas no necesitan un sufijo en especial.
Al reemplazar deliberadamente una excepción interna ("raise X from None" en Python 3.3+), asegúrese de que los detalles relevantes se transfieran a la nueva excepción (como preservar el nombre del atributo al convertir KeyError a AttributeError, o añadiendo el texto de la excepción original en el nuevo mensaje de excepción).
1 2 3 4 |
try: import platform_specific_module except ImportError: platform_specific_module = None |
Una simple cláusula except : capturará excepciones SystemExit y KeyboardInterrupt, lo que dificultará la interrupción de un programa con Control-C, y puede causar otros problemas. Si desea capturar todas las excepciones que señalan errores del programa, use except Exception: (El except es equivalente a except BaseException:).
Una buena regla general es limitar el uso de la simple cláusula 'except' a dos casos:
1. Si el manejador de excepciones se imprimirá o registrará la excepción; lo que significa que el usuario sabrá que se ha producido un error.
2. Si el código necesita hacer un trabajo de limpieza, pero luego deja que la excepción se propague hacia arriba con raise. try...finally puede ser una mejor manera para manejar este caso.
1 2 3 4 5 6 7 |
# Correcto: try: value = collection[key] except KeyError: return key_not_found(key) else: return handle_value(value) |
1 2 3 4 5 6 7 |
# Incorrecto: try: # ¡Muy extenso! return handle_value(collection[key]) except KeyError: # También capturará la excepción KeyError lanzada por handle_value() return key_not_found(key) |
1 2 3 |
# Correcto: with conn.begin_transaction(): do_stuff_in_transaction(conn) |
1 2 3 |
# Incorrecto: with conn: do_stuff_in_transaction(conn) |
El último ejemplo no proporciona ninguna información para indicar que los métodos __enter__ y __exit__ están haciendo algo más que cerrar la conexión después de una transacción. Ser explícito es importante en este caso.
1 2 3 4 5 6 7 8 9 10 |
# Correcto: def foo(x): if x >= 0: return math.sqrt(x) else: return None def bar(x): if x < 0: |
1 2 3 4 5 6 7 8 9 10 11 12 |
return None return math.sqrt(x) # Incorrecto: def foo(x): if x >= 0: return math.sqrt(x) def bar(x): if x < 0: return return math.sqrt(x) |
Los métodos de cadena siempre son mucho más rápidos y comparten la misma API con cadenas unicode. No use esta regla si se requiere compatibilidad con versiones anteriores a Python 2.0.
startswith() y endswith() son más limpios y menos propensos a errores:
1 2 |
# Correct: if foo.startswith('bar'): |
1 2 |
# Wrong: if foo[:3] == 'bar': |
Las comparaciones de tipos de objeto siempre deben usar isinstance() en lugar de comparar tipos directamente:
1 2 |
# Correcto: if isinstance(obj, int): |
1 2 |
# Incorrecto: if type(obj) is type(1): |
1 2 3 |
# Correcto: if not seq: if seq: |
1 2 3 |
# Incorrecto: if len(seq): if not len(seq): |
1 2 |
# Correcto: if greeting: |
1 2 |
# Incorrecto: if greeting == True: |
Y peor aún:
1 2 |
# Incorrecto: if greeting is True: |
Anotación de variables
Las anotaciones para variables a nivel de módulo, las variables de clase e instancia y las variables locales deben tener un solo espacio después del carácter de dos puntos (“: ”).
No debe haber espacio antes de los dos puntos.
Si una tarea tiene un lado derecho, entonces el signo igual (“=”) debe tener exactamente un espacio en ambos lados:
1 2 3 4 5 6 7 |
# Correcto: code: int class Point: coords: Tuple[int, int] label: str = '<unknown>' |
1 2 3 4 5 6 7 |
# Incorrecto: code:int # Sin espacios después de los dos puntos code : int # Espacio antes de los dos puntos class Test: result: int=0 # No hay espacios antes y después del signo igual |