PROJET AUTOBLOG


Sam & Max: Python, Django, Git et du cul

Site original : Sam & Max: Python, Django, Git et du cul

⇐ retour index

Comment garder des lignes courtes ? 16   Recently updated !

vendredi 28 avril 2017 à 15:02

Arg, j’ai plein de commentaires sans réponse sur le blog, indexerror aussi. Des tickets millénaires sur 0bin et les impôts qui arrivent. Des fois ce qu’il faut c’est une petit victoire pour relativiser.

Du coup, un petit post pour me donner l’impression de ne pas être inutile à l’humanité.

De toutes les recommandations du PEP8, garder des lignes courtes, souvent moins de 80 caractères, est celle qui fait le plus râler.

On rétorque parfois que c’est une règle qui n’a pas de sens de nos jours avec nos grands écrans HD.

Sauf que:

D’une manière générale, garder des lignes courtes est une bonne habitude et incitera à écrire un code sain. Le processus de réduire la taille des lignes passe par l’expressivité, la clarté, le refactoring, etc. Au final, c’est excellent pour la santé du projet.

N’oubliez pas non plus que le PEP8 indique clairement qu’il ne faut jamais suivre une règle de manière rigide. Si votre ligne est absolument plus adéquate sur une ligne, alors mettez la sur une ligne.

Maintenant qu’on a expliqué le pourquoi, parlons du comment. En effet beaucoup de bonnes pratiques ne sont pas appliquées parce qu’on ne sait pas faire. Faire des lignes courtes demande une certaine connaissance, et un peu de pratique.

Voici quelques pistes pour vous aider dans vos prochaines sessions.

Python est fait pour ça

Python force à indenter, et c’est une de ses meilleures caractéristiques. Jamais vous ne vous retrouverez comme dans d’autres langages face au code de votre collègue, ce gros porc, qui aligne ses accolades avec le groin.

Mais pour garder des lignes courtes, l’indentation joue contre vous.

Python vient heureusement avec tout un tas d’outils pour rendre votre code court, rapide et peu gourmand on mémoire. C’est tout bénef.

itertools, all(), any(), filter(), map(), collections, les listes en intension, functools et les générateurs sont tous d’excellents moyens de créer un code plus beau, plus court, et plus efficace. Apprenez à les utilisez ! Vous serez un meilleur programmeur, plus productif, et les lignes seront naturellement plus courtes.

Exemples…

Le module itertools permet de faire un tas de choses, comme remplacer les boucles imbriquées.

Remplaçons :

>>> for lettre in "abc":
...     for chiffre in (1, 2, 3):
...         print(lettre, chiffre)
...
a 1
a 2
a 3
b 1
b 2
b 3
c 1
c 2
c 3

Par :

>>> from itertools import product
>>> products = product("abc", (1, 2, 3))
>>> for lettre, chiffre in products:
...     print(lettre, chiffre)

Les built-ins ont un tas d’outils pour pour manipuler les données.

Si vous avez des collections dont vous voulez vérifier tout le contenu:

>>> from random import randint
>>> data = [randint(0, 10) for x in range(0, randint(0, 10))]
>>> max(data)  # pas besoin de boucler pour trouver le max
9
>>> if any(x > 3 for x in data): # any est un super "or"
...    print('Un élément est supérieur à 3')

Le module collections possède d’ailleurs tout un tas d’outils pour faire le travail à votre place :

>>> from collections import Counter
>>> Counter("aaaaaaaaabbbbbbccccc")
Counter({'a': 9, 'b': 6, 'c': 5})

On peut éviter un tas de try/except avec les helpers qui retournent une valeur par défaut:

>>> {"foo": 1}.get('bar', 3)  # et next, iter, setdefault... 
3

Sans parler de l’unpacking, le slicing, le paramétrage dynamique, etc.

Bref, si votre ligne est trop longue, c’est peut être parce que vous être en train de sous-utiliser Python.

De même, apprenez les libs les plus célèbres en Python.

pytest, pendulum, request, pandas…

Dès qu’un usage particulier intervient, elles seront généralement plus efficaces que la stdlib. Moins de code !

Refactorisez

Un bloc de code qui commence à être long sera avantageusement déplacé dans une méthode ou une fonction. Avec un joli nom bien explicite qui va naturellement rendre votre code mieux documenté, et testable.

Tant qu’on y est, faites usages des variables intermédiaires.

res = [foo for foo in objet.attribut['cle'] if foo > wololo]

Gagnera à devenir:

nom_explicite = objet.attribut['cle']
res = [foo for foo in nom_explicite if foo > wololo]

Les parenthèses pour les sauts de ligne

Les parenthèses en Python, c’est magique.

Avant :

from module_de_la_mort_qui_tue import foo, bar, et, toute, la, clique

Après

from module_de_la_mort_qui_tue import (
	foo, 
	bar, 
	et, 
	toute, 
	la, 
	clique
)

Ca marche partout, dans les appels de fonctions, l’accès des attributs, les chaînes de caractères…

On part de :

queryset = ModelDeDjango.objects.filter(attribut=val).first()

Et bim :

queryset = (ModelDeDjango.objects
                         .filter(attribut=val)
                         .first())

Si des parenthèses sont déjà là, inutile d’en rajouter:

Aller :

raise OverkillError("Arrrrrrrrrrrrrrrrrrrrrrrrrrrrggggggg")

Hop :

raise OverkillError(
	"Arrrrrrrrrrrrrrrrr"
	"rrrrrrrrrrrggggggg"
)

Aidez-vous de l’environnement

Vous outils sont là pour vous faciliter la vie. Votre éditeur par exemple, a certainement un moyen d’afficher un indicateur vertical pour symboliser la limite de 80 caractères.

Les bons IDES et les linters vous signalerons le dépassement. Ça vaut le coup d’investir dedans. Si votre éditeur ne le supporte pas par défaut, il a peut-être un plugin pour utiliser un linter.

VSCode et Sublime Text ont tous deux des plugins pour Python qui permettent cela. Notamment ils peuvent exploiter l’excellent linter flake8, qui sinon peut s’utiliser à la main.

Pour certaines lignes, vous allez dépasser. Ce n’est pas la mer à boire tant que c’est un choix conscient et pas de la flemme.

Par exemple, les commentaires avec des URLs dedans dépassent souvent. Beaucoup de linters ont un réglage pour les autoriser (ou un pattern au choix), activez-le.

Si vous avez une ligne qui dépasse et que le signalement de votre IDE/linter vous casse les couilles, il est souvent possible de le désactiver en ajoutant en fin de ligne le commentaire:

# noqa

Qui signifie tantôt “no question asked” ou “no quality assessment”.