Python Auto Formatter: Autopep8 vs. Black (y algunos consejos prácticos)

Dec 12 2022
Aquí está la conclusión: prefiero el negro como herramienta de formato automático, pero hay algunos consejos prácticos (al final) que debe tener en cuenta, y funciona mejor en paralelo con otras herramientas como isort. Introducción Autopep8 y Black son excelentes herramientas para formatear automáticamente su código Python para cumplir con la guía de estilo PEP 8.
Fotografía por autor

Aquí está la conclusión: prefiero el negro como herramienta de formato automático, pero hay algunos consejos prácticos (al final) que debe tener en cuenta, y funciona mejor en paralelo con otras herramientas como isort.

Introducción

Autopep8 y Black son excelentes herramientas para formatear automáticamente su código Python para cumplir con la guía de estilo PEP 8 . Black tiene 30.400 estrellas en GitHub y es probablemente la herramienta más popular de su tipo, mientras que autopep8 tiene 4.200 estrellas.

Una de las principales diferencias es que Black es un formateador obstinado, lo que significa que siempre convierte el código base completo en su propio estilo, mientras que autopep8 conserva el estilo de entrada hasta cierto punto y solo corrige las partes necesarias.

He usado ambas herramientas en mi trabajo y me gustaría compartir con ustedes por qué prefiero el negro sobre el autopep8.

Problemas con autopep8

1. Ordena las importaciones de forma agresiva

Algunos pueden ver esto como algo bueno, sin embargo, en mi opinión, una buena herramienta debe centrarse en una cosa y solo en una cosa. Como herramienta de formato, no debería intentar cambiar el orden del código y, de hecho, a veces puede causar problemas.

Consideremos el siguiente ejemplo. Aunque sys.path.appendgeneralmente no es una buena práctica, digamos que realmente queremos hacer algo antes de importar el resto de los módulos.

Autopep8 reescribiría el script de la siguiente manera:

Y esto es problemático. Otro ejemplo que se me ocurre es que si queremos habilitar el backend de matplotlib para una terminal de Linux, tendríamos que configurar el backend matplotlib.use("agg") antes de la importación de pyplot from matplotlib import pyplot as plt.

Por el contrario, el negro no cambiará el código de ejemplo anterior. Black solo formatea y la semántica del código sigue siendo exactamente la misma. En otras palabras, el negro no clasifica sus importaciones y no cambia el orden de su código. (y podemos dejar la tarea de clasificar las importaciones para otra gran herramienta isort , ¡continúe leyendo!)

Todavía puede resolver el problema agregando # nopep8algunos fragmentos de su código, diciéndole explícitamente a autopep8 que no lo toque:

Funciona en este caso, pero descubrí que la # nopep8regla de exclusión no se aplica a los comentarios, por ejemplo, autopep8 todavía convertiría lo siguiente ### some comment # nopep8en # some comment # nopep8.

Por otro lado, el negro no edita comentarios ni cadenas de documentos, y puede excluir parte de su código para que no se formatee agregando dos líneas de comentario # fmt: offy # fmt: onantes y después de su bloque de código.

De todos modos, no es muy pitónico, ¿verdad?

2. No aplica correctamente la sangría

La sangría predeterminada de Autopep8 se establece en el mismo tamaño de la pestaña de su editor, y puede especificar el valor pasando la opción autopep8 --indent-size 4 myfile.py. Todo está bien, sin embargo, autopep8 solo este valor de entrada para establecer la sangría para el comienzo de cada declaración, pero el tamaño de la sangría entre paréntesis siempre se establece en el tamaño de tabulación predeterminado.

Veamos este ejemplo, donde la sangría del código es 1 y el tamaño de pestaña predeterminado de mi editor es 4.

Después de establecer la sangría en 3 con autopep8 autopep8 --indent-size 3 format_02_raw.py -i (-i significa en su lugar) , obtenemos lo siguiente:

Podemos ver que la sangría en la primera función se establece correctamente en 3, pero todo lo que esté entre corchetes (en este caso, la declaración de impresión y la matriz) se establece en su lugar en el tamaño de pestaña predeterminado 4.

Descubrí esto porque el tamaño de pestaña predeterminado en mi entorno de trabajo es 2, y prefiero la sangría de 4. Puede sonar trivial, pero ¿por qué arriesgarse a la inconsistencia innecesaria? Black no le permite configurar el tamaño de la sangría, ya que siempre establece la sangría en 4 en todos los lugares, lo que no me importa en absoluto.

Usando el negro de la manera correcta

Black implementa su propio estilo, que a algunas personas les gusta y a otras no. Me gusta bastante porque en general es muy limpio y legible, pero hay dos cosas a tener en cuenta.

1. Usa una coma final

El siguiente ejemplo muestra probablemente una de las razones más comunes por las que a algunas personas no les gusta el negro. Veamos el antes y el después:

Es molesto, pero antes de que te enojes, hagamos algunos pequeños cambios en el código y veamos cómo el negro cambia su comportamiento:

Sí, el negro usa comas finales para decidir si los elementos se envolverán juntos o permanecerán en líneas nuevas. Si un elemento similar a una matriz termina sin una coma final, ya sea una lista, una matriz o un diccionario, el negro siempre intenta deformarlo en una sola línea; si excede la longitud de la línea, el negro coloca su contenido en líneas nuevas y agrega una coma final para usted . Si hay una coma final en el elemento, el negro separa su contenido en líneas nuevas para usted .

En resumen, siempre habrá una coma final dondequiera que el contenido de un elemento similar a una matriz esté en líneas nuevas. Creo que esto tiene sentido y, en general, las comas finales son una buena práctica, ya que hacen que el código sea más fácil de mantener, además de generar limpieza git diffcuando realiza cambios. Entonces, si no desea que el negro ajuste su código a una sola línea, ¡agregue una coma al final!

Consejos adicionales: cuando escribo consultas SQL, escribiría

SELECT column_a
      ,column_b
      ,column_c
FROM some_table

SELECT column_a,
       column_b,
       column_c
FROM some_table

2. Especifique la longitud de la línea si es necesario

Lo único que no me gusta del estilo de código negro hasta ahora es con respecto a las declaraciones if largas, como muestra el siguiente ejemplo:

Reforzó la consistencia pero sacrificó la legibilidad. La longitud de línea predeterminada de Black es 88, pero a veces tengo declaraciones un poco más largas y no quiero que tengan ese formato.

Mi solución es permitir una longitud de línea ligeramente más larga. Podemos especificar la longitud de la línea usando --line-lengtho -lbandera, y si establecemos la longitud de la línea en 100 black -l 100 format_05_raw.py, el ejemplo anterior no se reformateará. Según mi experiencia, una longitud de línea de 100 se adaptaría a la mayoría de las declaraciones largas y al mismo tiempo conservaría una buena legibilidad del código (aunque realmente debería considerar volver a escribir su declaración si tiene más de 100 caracteres), pero, por supuesto, esto depende de cada equipo para decidir .

Autopep8 también tiene una bandera de este tipo --max-line-length, sin embargo, como autotpep8 tiende a conservar el estilo del código original, el resultado del formato es mucho menos sensible a la longitud de línea especificada que el negro.

3. Usa negro con isort

Como mencioné anteriormente, el negro no clasifica sus importaciones, y podemos usar isort (5.4k estrellas en GitHub) para hacer esto. Veamos un ejemplo rápido de lo que puede hacer isort:

Es limpio y no estropea nuestro sys.path.appendejemplo.

Tenga en cuenta que existen algunas pequeñas diferencias entre cómo isort y black organizan las importaciones, y podemos decirle a isort que ordene las importaciones de acuerdo con el estilo del código black isort --profile black format_06_raw.py.

Ahora tenemos un flujo de trabajo bastante bueno: use isort para ordenar las importaciones primero y luego use black para formatear nuestro código. Podemos combinar los dos pasos juntos en Makefile:

format:
 isort --profile black src/
 black -l 100 src/

Conclusión

En este artículo comparamos dos herramientas populares de formateo automático en Python: autopep8 y black. Expliqué por qué prefiero el negro y cómo me gusta usarlo, y espero que esto sea útil.

Esta es también la primera vez que escribo un artículo en Medium, no dudes en darme un aplauso si te gusta y no olvides dejar tus comentarios a continuación, ¡hasta la próxima!