ProPython
Ecrire du code "Pythonic", clair et compréhensible
10 Oct, 2021

Ecrire du code "Pythonic", clair et compréhensible

Avec Python, il est relativement facile de développer des programmes fonctionnels en peu de lignes. En revanche, pour des programmes plus complexes, il faut optimiser son code et le rendre le plus compréhensible possible. Nous allons voir dans cet article quelques astuces pour parvenir à cet objectif.

Généralités

En Python, et dans tout autre langage, il ne s'agit pas de faire uniquement un code qui fonctionne. Il faut que le code soit lisible, efficace, et maintenable dans le temps.

Pour cela, il faut que le code se documente lui-même. C'est à dire que vous pouvez le comprendre simplement en le lisant. Prenons un exemple :

def mystery(n):
   if n <= 1:
       return n
   else:
       return(mystery(n-1) + mystery(n-2))

Est-ce que vous comprenez ce que fait cette fonction ? Je ne pense pas. L'objectif va donc être de réécrire cette fonction de sorte que tout le monde puisse comprendre ce qu'elle fait. Regardez la fonction suivante :

def calculate_n_term_fibonacci(n):     
    u0 = 0
    u1 = 1
    fibonaccis = [u0, u1]    
                                                                                       
    for f in range(1, n):                                                                           
        fibonaccis.append(fibonaccis[-1] + fibonaccis[-2])  
                                                                       
    return fibonaccis[n]

Ceux qui ont fait un peu de maths comprendront assez facilement ce que fait cette fonction : elle calcule le n-ième terme de la suite de fibonacci. Mais qu'est-ce qui a changé pour que la fonction devienne plus compréhensible ?

Les noms

Il faut toujours choisir des noms explicites, qui représentent l'objet qu'on manipule et qui permettent de comprendre diretement son utilité.

Pour une variable, il faut choisir un nom représentatif. Pour une fonction, il faut choisir un nom qui décrit ce qu'elle fait. Pour une classe, il faut choisir un nom qui représente le rôle de la classe.

Par exemple, imaginons une classe qui permet de gérer des dates comprenant des temps (ex: 01/01/2022 00:00). On pourrait l'appeler Date, ce ne serait pas faux. Mais ce ne serait pas complet, le mieux est de l'appeler Datetime car on comprend directement qu'elle gère à la fois la date et le temps.

La logique

Il faut essayer au maximum de résoudre les problèmes de la façon la plus logique et la plus intuitive possible. Si on reprend notre exemple plus haut, la première fonction résoud notre problème de façon récursive. Evidemment on ne pense normalement pas à ça en premier, la méthode la plus simple étant quasiment toujours la méthode itérative. C'est pour cela que quand vous avez lu le code, vous n'avez normalement pas compris ce que fait la fonction. En revanche dans le deuxième cas, c'est beaucoup plus intuitif et compréhensible.

Bien sûr cela ne s'applique pas qu'aux fonctions récursives, mais est extensible pour absolument tout en programmation : lorsque vous devez résoudre un problème, ne cherchez pas compliqué, résolvez le de la façon la plus simple possible et celle à laquelle tout le monde pense.

Le formattage

Finalement, le formattage du code est très important. Il faut rassembler les blocs qui vont ensemble, et les espacer de ceux qui ne sont pas liés. Cela n'est pas visible dans notre exemple, mais imaginons que vous déclarez 3-4 variables, et qu'ensuite vous effectuez plusieurs opérations avec. Vous allez séparer la déclaration des variables des opérations.

En bref, faites des blocs dans votre code, et ces blocs doivent rassembler les éléments liés entre eux.

La granularité

Il faut essayer de diviser les éléments du code de la façon la plus granulaire possible (pour la programmation orientée objet en tout cas). C'est à dire qu'une classe ne doit avoir qu'une seule responsabilité et ne servir qu'à une chose, de même qu'une fonction ne doit faire qu'une seule chose.

Cela permet de comprendre directement l'utilité de chaque élément du code, et aussi d'être très flexible dans la maintenance et le développement car les modifications du code sont centralisées. Par exemple, si vous faites la même action plusieurs fois dans le code, il est bien de faire une fonction et de l'utiliser 3 fois, comme ça si vous souhaitez modifier les actions effectuées vous ne les modifiez qu'une seule fois plutôt que de le faire 3 fois.

Les commentaires

Certains vous diront de commenter chaque bout de code. En Python, on utilise souvent les docstrings pour documenter chaque classe, chaque fonction; je ne vous recommande pas de faire ça. Il est mieux de faire un code qui se documente tout seul comme je l'explique plus haut que de faire un code pas clair et de tout expliquer avec des commentaires. Les commentaires utiles sont ceux qui donnent une information qui n'est pas trouvable dans le code, par exemple une prise de décision (pourquoi une solution récursive a-t-elle été choisie au lieu d'une solution itérative par exemple), l'explication d'un paramètre de fonction ambigü, ou même un commentaire TODO.

Retenez que le meilleur commentaire est celui que vous n'avez pas à écrire.

Généralités appliquées au Python

Bien, maintenant que nous savons comment écrire du bon code, il faut appliquer ceci au Python.

Sachez déjà que Python permet de nombreux raccourcis mais attention il faut es utiliser avec parcimonie car ils peuvent quelques fois diminuer la clarté du code. Vous connaissez déjà une grande partie de ces raccourcis, mais il faut penser à les utiliser en pratique, et les utiliser à bon escient. Un exemple :

a = 5
if a > 3:
  return True
else:
  return False

Ce code vous paraît bon ? Peut-être que si vous avez déjà fait du C, vous ne voyez pas de problème. En revanche, en Python on peut écrire directement :

a = 5
return a > 3

Maintenant, est-ce que ce code est plus clair ? Objectivement non, mais pour quelqu'un qui fait du Python c'est la syntaxe à préférer, et c'est celle que vous trouverez plus claire à force de vous entraîner. Il faut donc vous efforcer d'utiliser ce genre de raccourcis ; même s'ils paraissent moins clair, c'est en fait la syntaxe que tout le monde adopte et c'est la plus simple car la plus courte.

Autre exemple :

def x_is_greater_than_4(x):
    return x > 4

Une telle fonction peut être utile si vous souhaitez filtrer une liste par exemple. Comment la réécrire de façon plus "Pythonic" ?

x_is_greater_than_4 = lambda x: x > 4

Encore une fois cela peut paraître moins clair, mais c'est la solution vers laquelle il faut s'orienter en Python.

Dernier exemple, cette méthode (qui fait partie d'une classe qu'on va nommer Datetime) :

def get_actual_datetime(self):
    return dt.datetime.now()

Est-ce que vous arrivez à trouver le problème ? Il y a un paramètre en trop, le self. Mais on ne peut pas se débarrasser de ce paramètre car notre fonction est en fait une méthode d'instance. Ca pose un autre problème : on a besoin d'instancier un objet pour utiliser cette fonction, alors que ce n'est pas logique puisque cette fonction n'a aucun lien avec l'objet instancié. C'est pour cela qu'existent les méthodes statiques : elles permettent de dire que la méthode n'utilise pas d'instance. Pour cela on utilise simplement le décorateur @staticmethod. La fonction devient donc :

@staticmethod
def get_actual_datetime():
    return dt.datetime.now()

Et nous n'avons plus besoin du paramètre self ! Notre fonction s'utilisera donc de la façon suivante : Datetime.get_actual_datetime(). Encore une fois, on peut se demander si c'est pertinent de mettre cette fonction ici dans cette classe en tant que méthode statique. Eh bien, ou la mettre si ce n'est là ? C'est totalement cohérent de la mettre dans cette classe.

Le mot de la fin

Vous avez maintenant les bases pour commencer à faire du code clair et bien structuré. Je ferai un exercice prochainement qui vous permettra de pratiquer et de refacto un peu de code.

Si cet article vous a plus, n'hésitez pas à me faire un retour par commentaire ou par mail.

On se retrouve prochainement pour de nouvelles astuces !

Laisser un commentaire

Premium - 15€/mois

L'accès à des articles inédits, à une multitude de ressources, à de nouveaux projets, mais également à des vidéos explicatives, découvrez ici pourquoi passer premium.

Articles liés

Catégories

Ressources

Retrouvez une collection de ressources (des scripts, des fiches résumé, des images...) liées aux articles du blog ou au Python.
Voir

Contact

contact@propython.fr
Se connecter pour envoyer un message directement depuis le site.

Navigation

AccueilSe connecterCréer un compteRessourcesPremium

Catégories

Pages légales

Politique de confidentialitéMentions légalesConditions générales de vente