Estilo de codificación y buenas prácticas

Además de una correcta y ordenada estructura general que deben tener los programa, es conveniente mantener ciertas buenas prácticas de codificación y el estilo de codificación recomendado. Estas normas no son obligatorias, como lo es la propia sintaxis del lenguaje, pero conviene seguir las recomendaciones de los desarrolladores de Python para facilitar la lectura del programa y ayudar a encontrar posibles errores.

Un ejemplo básico para entender a lo que nos referimos es el sangrado, que como hemos visto en Python en obligatorio, pero mientras la estructura de bloques sea correcta, a Python no le importa el número de espacios que se usen. Pues bien, aunque a Python le da igual, la recomendación es usar cuatro espacios (no tabuladores) para la sangrar bloques. Hay otras normas similares muy sencillas que debemos intentar seguir, como estas:

Cuando sea posible, define variables con nombres que tengan algún sentido o que puedas identificar fácilmente, no importa que sean más largas. Por ejemplo, en un programa podría­amos escribir:

a = 10.  # altura
b = 3.5  # base
print("El volumen es %.1f" % (a*b))

pero, ¿qué significan a y b? lo sabemos por el comentario (bien hecho), pero si más adelante nos encontramos con esas variables, tendremos que recordar cual es cual. Es mejor usar nombres con significado:

altura = 10.
base = 3.5
print("El volumen es %.1f" % (altura*base))

De hecho podemos usar el nombre para dar más información sobre la variable:

velocidad_metros_segundo = 12.5
angulo_radianes = 1.3

Las lí­neas de codigo no deben ser muy largas, como mucho 72 caracteres. Si se tiene una línea larga, se puede cortar con una barra invertida (\) y continuar en la siguiente línea:

print("Esta es una frase muy larga, se puede cortar con una \
       y seguir en la línea inferior.")

Dentro de paréntesis, corchetes o llaves, no dejar espacios inmediatamente dentro de ellos:

:  funcion(num[1], {pares: 2})
NO:  funcion( num[ 1 ], { pares: 2 } )

Justo después de coma, punto y coma y punto, separar con un espacio, para mayor claridad, pero no antes:

:  print x, y; x, y = y, x
NO:  print x , y ; x , y = y , x

Aunque en Python se pueden hacer varias declaraciones en una línea, se recomienda hacer sólo una en cada línea:

:  a = 10
     b = 20
NO:  a = 10; b = 20

:  if a > 3.14:
        print(a)
NO:  if a > 3.14: print(a)

Manipulación de listas

Aunque combinar iterables con elementos de control de flujo para manipular listas es muy sencillo con Python, hay métodos específicos más eficientes para hacer lo mismo. Pensemos el fitrado de datos de una lista:

# Seleccionar los números positivos
numeros = [-3, 2, 1, -8, -2, 7]
positivos = []
for i in positivos:
    if i > 4:
        positivos.append(i)

Aunque técnicamente es correcto, es más eficiente hacer algo como esto usando las posibilidades de Python:

numeros = [-3, 2, 1, -8, -2, 7]
positivos = [i for i in a if i > 4]

# o también:
positivos = filter(lambda x: x > 4, numeros)

Igualmente, aunque se puede hacer esto:

# Suma 3 a cada elemento de la lista
numeros = [-3, 2, 1, -8, -2, 7]
for i in range(len(numeros)):
    numeros[i] += 3

Es mejor hacer esto otro:

numeros = [-3, 2, 1, -8, -2, 7]
numeros = [i + 3 for i in numeros]

# o también:
numeros = map(lambda i: i + 3, numeros)

Documentación de código

Casi tan importante como la escritura de código, es su correcta documentación, una parte fundamental de cualquier programa que a menudo se infravalora o simplemente se ignora. Aparte de los comentarios entre el código explicando cómo funciona, el elemento básico de documentación de Python es el Docstring o cadena de documentación, que ya hemos visto. Simplemente es una cadena de texto con triple comillas que se coloca justo después de la definición de función o clase (ver programación orientada objetos, más adelante) que sirve de documentación a ese elemento.

def potencia(x, y):
    """
    Calcula la potencia arbitraria de un número
    """

    return x**y

  # Acceso a la documentación
  potencia.__doc__
  help(potencia)

Además de esta documentación básica, lo correcto es detallar mejor en el Docstring qué hace y cómo se usa la función o clase y los parámetros que necesita. Se recomienda usar el estilo de documentación del software de documentación sphinx, que emplea reStructuredText como lenguaje de marcado.

Veamos un ejemplo de una función bien documentada:

"""
power(x1, x2[, out])

First array elements raised to powers from second array, element-wise.

Raise each base in `x1` to the positionally-corresponding power in
`x2`.  `x1` and `x2` must be broadcastable to the same shape. Note that an
integer type raised to a negative integer power will raise a ValueError.

Parameters
----------
x1 : array_like
    The bases.
x2 : array_like
    The exponents.

Returns
-------
y : ndarray
    The bases in `x1` raised to the exponents in `x2`.

See Also
--------
float_power : power function that promotes integers to float

Examples
--------
Cube each element in a list.

>>> x1 = range(6)
>>> x1
[0, 1, 2, 3, 4, 5]
>>> np.power(x1, 3)
array([  0,   1,   8,  27,  64, 125])

Raise the bases to different exponents.

>>> x2 = [1.0, 2.0, 3.0, 3.0, 2.0, 1.0]
>>> np.power(x1, x2)
array([  0.,   1.,   8.,  27.,  16.,   5.])

The effect of broadcasting.

>>> x2 = np.array([[1, 2, 3, 3, 2, 1], [1, 2, 3, 3, 2, 1]])
>>> x2
array([[1, 2, 3, 3, 2, 1],
       [1, 2, 3, 3, 2, 1]])
>>> np.power(x1, x2)
array([[ 0,  1,  8, 27, 16,  5],
       [ 0,  1,  8, 27, 16,  5]])
"""

En este ejemplo de la función power() de numpy no solo se explica qué hace la función, sino que indica los parámetros de entrada y salida e incluso da algunos ejemplos de uso.