Una colección de las buenas prácticas en python para programar de una forma más estandarizada o más idiomática, especialmente si somos nuevos en python.

Documentación y comentarios adecuados

Es el primer y más importante punto al que debemos poner atención tener buenas prácticas en python. Cualquier código que escribamos debe estar bien documentado y comentado. Pero, ¿Por qué necesitamos la documentación del código? Un proyecto de una empresa puede durar años y estar desarrollado por varias personas. Los nuevos desarrolladores se unen al proyecto en cualquier momento, por lo que necesitarán saber y comprender el código. Simplemente pueden consultarlo y obtendrán una comprensión clara del código. Pensemos siempre en el próximo desarrollador si no hay documentación donde solamente hay código, sería realmente difícil seguir el desarrollo. Comentar también tiene el mismo propósito, debemos agregar comentarios en el código donde sea necesario.

Hay tres tipos de comentarios:

Comentario de una sola línea: comienzan con el símbolo del hashtag (#) y termina hasta el final de la línea.

# Esto es un comentario
# Imprime ¡Hola Mundo!
print('¡Hola mundo!')

Comentario de varias líneas: es un texto de varias líneas delimitado por (""") en cada extremo del comentario. No debe haber espacios en blanco entre el delimitador (""").

"""
Este es un comentario de varias líneas,
abarcando tres líneas.
Aquí termina.
"""

print('¡Hola mundo!')

Comentarios de Docstring: Es una característica incorporada de python. Se utiliza para asociar documentación que se ha escrito con módulos, funciones, clases y métodos. Se usa justo debajo de las funciones, módulos, clases para decir lo que están haciendo. El comentario de la cadena de documentación está disponible mediante el atributo _doc_.

def add(a, b):
    """
    Define sobre qué trata la función
    La suma de dos números a y b.
    """
    return a + b

print(add.__doc__) # Imprime el comentario que hay dentro de  la función

Introducir excepciones

Python utiliza un objeto especial llamado exception para controlar cualquier error que pueda ocurrir durante la ejecución de un programa.

Cuando ocurre un error durante la ejecución de un programa, Python crea una excepción. Si no se controla esta excepción la ejecución del programa se detiene y se muestra el error.

Para evitar la interrución de la ejecución del programa cuando se produce un error, es posible controlar la exepción que se genera con la instrucción try – except – else y hay buenas prácticas al respecto:

# mala practica
try:
    hacer_algo()
except:
    pass

# Una forma ligeramente mejor (incluido el registro), pero sigue siendo una mala práctica:
try:
    hacer_algo()
except Exception:
    logging.exception() # aunque, logging es una buena práctica

# Cuando no usamos 'Exception`, también estaremos capturando eventos como la salida del sistema.
# Entonces, usar Exception significa que solo estamos capturando excepciones.

# Una mejor forma:
try:
    hacer_algo()
except ValueError: # Aquí hemos utilizado un tipo específico de excepción, es decir, ValueError
    logging.exception()
    # algún código para manejar su excepción  si es necesario

Convención de nombres

En python, se prefiere snake_case para variables, funciones y nombres de métodos. Sin embargo, para las clases se utiliza PascalCase.

# usar camelCase no es una convención en python para funciones
def isEmpty(sampleArr):
    ...
# en lugar de eso usa snake_case 
def is_empty(sample_arr):
    ...

Operadores de comparación

Hay varias formas de comparar en Python:

# No hacer esto:
if 0 < x and x < 10:
    print('x es mayor que  0 pero menor que 10')


# Lo siguiente es buena práctica:
if 0 < x < 10:
    print('x es mayor que  0 pero menor que 10')

Argumentos predeterminados mutables

Consideremos el siguiente ejemplo de código:

def add_fruit(fruit, box=[]):
    box.append(fruit)
    return box

red_box = add_fruit("apple")
print(f"red box: {red_box}")

yellow_box = add_fruit("mango")
print(f"yellow box: {yellow_box}")

Entendamos paso a paso lo que está sucediendo:

  • Estamos creando una función para agregar frutas (str) en una caja box(list)
  • Hay una función add_fruit que es responsable de agregar la fruta
  • Esta función toma 2 argumentos: fruta y caja.
  • ¡Atención! : El segundo argumento aquí es un argumento predeterminado mutable.

Entonces, ¿qué es el argumento predeterminado mutable?
Un argumento en una función con valor predeterminado como mutable. En resumen, Python tiene tipos mutables e inmutables. La diferencia es:

  • los mutables se pueden modificar
  • los inmutables no se pueden modificar.

Lo que pasa en el código anterior es que se crea una nueva lista una vez que se define la función y se utiliza la misma lista en cada llamada sucesiva. Por lo que se usa un misma caja para cualqier fruta. Una buena práctica sería:

def add_fruit(fruit, box=None):
    if box is None:
        box = []

    box.append(fruit)
    return box

red_box = add_fruit("apple")
print(f"red box: {red_box}")

yellow_box = add_fruit("mango")
print(f"yellow box: {yellow_box}")

Formato tipo string

La f en f-strings también puede significar «rápido». f-strings es más rápido que %-formatting y str.format(). Por ejemplo:

# Evita usar
# %-formatting
name = "James Bond"
profession = "Secret Agent"
print("Hello, %s. You are a %s." % (name, profession))

# Bueno, pero no mejor
# str.format()
print("Hello, {}. You are a {}.".format(name, profession))

# Corto y mucho mejor que las anteriores!
# f-strings
print(f"Hello, {name}. You are a {profession}.")

Entorno de script de nivel superior

Se ejecuta solo si se ejecuta como un script y no como un módulo, Hola mundo! no se imprimirá si el módulo se importa a cualquier otro módulo.

# Filename: run.py

if __name__ == '__main__':
    print('Hola mundo!')

# $ python run.py
# $ Hola mundo!

Expresiones condicionales

Una expresión condicional en Python es una expresión (en otras palabras, un fragmento de código que se evalúa como un resultado) cuyo valor depende de una condición. Pero la lectura debe ser intuitiva.

# Mala práctica
if x < 10:
    return 1
else:
    return 2

# Buena práctica
return 1 if x < 10 else 2

Iterando sobre iteradores

No se necesita iterar sobre los índices de los elementos en un iterador si no es necesario. Podemos iterar directamente sobre los elementos.

list_of_fruits = ["apple", "pear", "orange"]

# mala práctica
for i in range(len(list_of_fruits)):
    fruit = list_of_fruits[i]
    process_fruit(fruit)

# buena práctica
for fruit in list_of_fruits:
    process_fruit(fruit)

Indexación y conteo durante la iteración

Si vemos código de python desde un programador de C o Java, es posible que los bucles for de Python le confundan. Python en realidad no tiene bucles for, al menos no el mismo tipo de bucle for que tienen los lenguajes basados en C. Los bucles for de Python son en realidad bucles foreach.

# No usar:
index = 0
for value in collection:
    print(index, value)
    index += 1


# Tampoco usar:
for index in range(len(collection)):
    value = collection[index]
    print(index, value)

# Definitivamente no usar esto:
index = 0
while index < len(collection):
    value = collection[index]
    print(index, value)
    index += 1

# En este caso, usar `enumerate()`
for index, value in enumerate(collection):
    print(index, value)

Uso de administradores de contexto

Python proporciona administradores de contexto que administran los gastos generales de inicialización y limpieza de los recursos y nos permiten enfocarnos en la implementación. Por ejemplo, en el caso de leer un archivo, no es necesario preocuparse
por cerrar el archivo manualmente.

d = {"foo": 1}

# mala práctica
f = open("./data.csv", "wb")
f.write("some data")

v = d["bar"] # KeyError
# f.close() nunca se ejecuta, lo que conduce a problemas de memoria
f.close()

# buena práctica
with open("./data.csv", "wb") as f:
    f.write("some data")
    v = d["bar"]
# python aún ejecuta f.close() incluso si ocurre la excepción KeyError

Usar set para buscar en lugar de list

Los conjuntos se implementan usando hash en python, lo que hace que la búsqueda de elementos sea más rápida (O (1)) en comparación con la búsqueda en un lista(O(n)).

s = set(['s', 'p', 'a', 'm'])
l = ['s', 'p', 'a', 'm']

# Esta bien para un número pequeño de elementos
def lookup_list(l):
return 's' in l # O(n)


# Mejor para un número muy grande de elementos
def lookup_set(s):
return 's' in s # O(1)

Usando * al importar un módulo

Las importaciones siempre deben ser específicas. Import * desde un módulo es una práctica muy mala que contamina el espacio de nombres de funciones clases, etc.

# mala práctica
from math import *
x = ceil(x)

# buena práctica
from math import ceil   
x = ceil(x) # we know where ceil comes from

usando items() para iterar un diccionario

d = {
     "name": "Aarya", 
     "age": 13
 }

# No hacer esto
for key in d:
    print(f"{key} = {d[key]}")

# mejor hacer esto
for key,val in d.items():
    print(f"{key} = {val}")

Si hay un gran número de buenas prácticas en python, Google pone a disposición una guía de estilo de buenas prácticas aquí.

Deja un comentario

Tu dirección de correo electrónico no será publicada.