Python Auto Formatter : Autopep8 contre Black (et quelques conseils pratiques)

Dec 12 2022
Voici la conclusion : je préfère le noir comme outil de formatage automatique, mais il y a quelques conseils pratiques (à la fin) que vous devriez garder à l'esprit, et cela fonctionne mieux en parallèle avec d'autres outils comme isort. Introduction Autopep8 et Black sont tous deux d'excellents outils pour formater automatiquement votre code Python afin qu'il soit conforme au guide de style PEP 8.
Photographie par l'auteur

Voici la conclusion : je préfère le noir comme outil de formatage automatique, mais il y a quelques conseils pratiques (à la fin) que vous devriez garder à l'esprit, et cela fonctionne mieux en parallèle avec d'autres outils comme isort.

Introduction

Autopep8 et Black sont tous deux d'excellents outils pour formater automatiquement votre code Python afin qu'il soit conforme au guide de style PEP 8 . Black a 30,4k étoiles sur GitHub et est probablement l'outil le plus populaire de son genre, tandis qu'autopep8 a 4,2k étoiles.

L'une des principales différences est que le noir est un formateur avisé, ce qui signifie qu'il convertit toujours l'intégralité de la base de code dans son propre style, alors qu'autopep8 préserve le style d'entrée dans une certaine mesure et ne corrige que les parties nécessaires.

J'ai utilisé les deux outils dans mon travail et j'aimerais partager avec vous pourquoi je préfère le noir à autopep8.

Problèmes avec autopep8

1. Il trie les importations de manière agressive

Certains peuvent voir cela comme une bonne chose, cependant, à mon avis, un bon outil doit se concentrer sur une chose et une seule chose. En tant qu'outil de formatage, il ne doit pas essayer de modifier l'ordre du code, et en effet, cela peut parfois causer des problèmes.

Considérons l'exemple ci-dessous. Bien que sys.path.appendce ne soit généralement pas une bonne pratique, mais disons simplement que nous voulons vraiment faire quelque chose avant d'importer le reste des modules.

Autopep8 réécrirait le script comme suit :

Et cela est problématique. Un autre exemple auquel je peux penser est que si nous voulons activer le backend de matplotlib pour un terminal Linux, nous aurions besoin de définir le backend matplotlib.use("agg") avant le pyplot import from matplotlib import pyplot as plt.

En revanche, le noir ne changera pas l'exemple de code ci-dessus. Le noir ne fait que le formatage et la sémantique du code reste exactement la même. En d'autres termes, le noir ne trie pas vos importations et ne modifie pas l'ordre de votre code. (et nous pouvons laisser la tâche de trier les importations à un autre excellent outil isort , veuillez continuer à lire !)

Vous pouvez toujours résoudre le problème en ajoutant # nopep8à certains extraits de votre code, en disant explicitement à autopep8 de ne pas y toucher :

Cela fonctionne dans ce cas, mais j'ai constaté que la # nopep8règle d'exclusion n'est pas appliquée aux commentaires, par exemple, autopep8 convertirait toujours ce qui suit ### some comment # nopep8en # some comment # nopep8.

D'autre part, le noir ne modifie pas les commentaires et les docstrings, et vous pouvez exclure certains de vos codes du formatage en ajoutant deux lignes de commentaires # fmt: offet # fmt: onavant et après votre bloc de code.

Quoi qu'il en soit, ce n'est pas très pythonique, n'est-ce pas ?

2. Il n'applique pas correctement l'indentation

L'indentation par défaut d'Autopep8 est identique à la taille de tabulation de votre éditeur, et vous pouvez spécifier la valeur en passant l'option autopep8 --indent-size 4 myfile.py. Tout va bien, cependant, autopep8 utilise uniquement cette valeur d'entrée pour définir l'indentation au début de chaque instruction, mais la taille de l'indentation entre parenthèses est toujours définie sur la taille de tabulation par défaut.

Regardons cet exemple, où l'indentation du code est 1 et la taille de tabulation par défaut de mon éditeur est 4.

Après avoir défini l'indentation sur 3 avec autopep8 autopep8 --indent-size 3 format_02_raw.py -i (-i signifie en place) , nous obtenons ce qui suit :

Nous pouvons voir que l'indentation dans la première fonction est correctement définie sur 3, mais tout ce qui se trouve entre parenthèses (dans ce cas, l'instruction d'impression et la matrice) est à la place défini sur la taille de tabulation par défaut 4.

J'ai découvert cela parce que la taille d'onglet par défaut dans mon environnement de travail est de 2 et que je préfère l'indentation de 4. Cela peut sembler trivial, mais pourquoi risquer une incohérence inutile ? Le noir ne vous permet pas de configurer la taille de l'indentation, car il définit toujours l'indentation sur 4 à tous les endroits, ce qui ne me dérange pas du tout.

Utiliser le noir de la bonne façon

Le noir met en œuvre son propre style, que certaines personnes aiment et d'autres non. Je l'aime bien car il est généralement très propre et lisible, mais il y a deux choses à garder à l'esprit.

1. Utilisez une virgule finale

L'exemple ci-dessous montre probablement l'une des raisons les plus courantes pour lesquelles certaines personnes n'aiment pas le noir. Regardons l'avant et l'après :

C'est ennuyeux, mais avant de vous fâcher, apportons quelques petites modifications au code et voyons comment le noir modifie son comportement :

Oui, le noir utilise des virgules de fin pour décider si les éléments seront regroupés ou resteront dans de nouvelles lignes. Si un élément de type tableau se termine sans virgule finale, qu'il s'agisse d'une liste, d'une matrice ou d'un dictionnaire, noir essaie toujours de le déformer en une seule ligne ; s'il dépasse la longueur de la ligne, noir met alors son contenu dans de nouvelles lignes et ajoute une virgule de fin pour vous . S'il y a une virgule à la fin de l'élément, le noir sépare son contenu en nouvelles lignes pour vous .

En bref, il y aura toujours une virgule de fin partout où le contenu d'un élément de type tableau se trouve dans de nouvelles lignes. Je pense que cela a du sens et, en général, les virgules de fin sont une bonne pratique car elles facilitent la maintenance du code et génèrent un nettoyage git difflorsque vous apportez des modifications. Donc, si vous ne voulez pas que le noir enveloppe votre code sur une seule ligne, ajoutez une virgule à la fin !

Astuces bonus : lorsque j'écris des requêtes SQL, j'écris

SELECT column_a
      ,column_b
      ,column_c
FROM some_table

SELECT column_a,
       column_b,
       column_c
FROM some_table

2. Spécifiez la longueur de la ligne si nécessaire

La seule chose que je n'aime pas dans le style de code noir jusqu'à présent concerne les longues instructions if, comme le montre l'exemple ci-dessous :

Cela a renforcé la cohérence mais a sacrifié la lisibilité. La longueur de ligne par défaut de Black est de 88, mais parfois j'ai des déclarations légèrement plus longues et je ne veux pas qu'elles soient formatées de cette façon.

Ma solution est de permettre une longueur de ligne légèrement plus longue. Nous pouvons spécifier la longueur de ligne en utilisant --line-lengthou -lflag, et si nous définissons la longueur de ligne sur 100 black -l 100 format_05_raw.py, l'exemple ci-dessus ne sera pas reformaté. D'après mon expérience, une longueur de ligne de 100 devrait convenir à la plupart des déclarations longues tout en conservant une bonne lisibilité du code (bien que vous devriez vraiment envisager de réécrire votre déclaration si elle fait plus de 100 caractères), mais bien sûr, c'est à chaque équipe de décider .

Autopep8 a également un tel indicateur --max-line-length, cependant, comme autotpep8 a tendance à conserver le style de code d'origine, le résultat de la mise en forme est beaucoup moins sensible à la longueur de ligne spécifiée que le noir.

3. Utilisez du noir avec isort

Comme je l'ai mentionné plus tôt, le noir ne trie pas vos importations, et nous pouvons utiliser isort (5,4k étoiles sur GitHub) pour ce faire. Regardons un exemple rapide de ce que peut faire isort :

C'est soigné et cela ne gâche pas notre sys.path.appendexemple.

Notez qu'il existe de légères différences entre la façon dont isort et black organisent les importations, et nous pouvons dire à isort de trier les importations conformément au style de code noir isort --profile black format_06_raw.py.

Nous avons maintenant un assez bon flux de travail : utilisez d'abord isort pour trier les importations, puis utilisez le noir pour formater notre code. Nous pouvons combiner les deux étapes ensemble dans Makefile :

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

Conclusion

Dans cet article, nous avons comparé deux outils de formatage automatique populaires en Python - autopep8 et black. J'ai expliqué pourquoi je préfère le noir et comment j'aime l'utiliser, et j'espère que cela vous sera utile.

C'est aussi la première fois que j'écris un article sur Medium, n'hésitez pas à m'applaudir si vous l'aimez et n'oubliez pas de laisser vos commentaires ci-dessous, et je vous verrai la prochaine fois !