2023-07-04 19:55 Temps de lecture : 18 min

Comment le Zen de Python peut vous aider à écrire un meilleur code

Souhaitez-vous perfectionner votre pratique de programmation en Python ? Voici comment les préceptes du Zen de Python peuvent vous guider vers cet objectif.

Python est réputé pour sa facilité d'apprentissage. Toutefois, la rédaction d'un code idiomatique, propre à Python, et facile à maintenir peut s'avérer délicate, surtout pour les développeurs débutants. Le PEP-20 a introduit "Le Zen de Python", un poème de Tim Peters, qui met en lumière l'importance d'écrire un code "Pythonic" respectant les meilleures pratiques.

Pour découvrir le Zen de Python, lancez un interpréteur Python (REPL) et exécutez la commande suivante :

>>> import this
The Zen of Python, by Tim Peters

Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!

Comme vous pouvez le constater, la plupart des aphorismes du Zen de Python sont intuitifs. Certains aphorismes doivent être interprétés conjointement avec le suivant, tandis que d'autres semblent contredire un aphorisme précédent. Néanmoins, le Zen de Python est une lecture à la fois agréable, stimulante et utile !

Interprétation du Zen de Python

Il a été avancé que le Zen de Python contient 20 principes fondamentaux pour la programmation en Python. Cependant, il n'y a que 19 aphorismes connus à ce jour. Examinons-les de plus près.

La beauté est préférable à la laideur.

Cet aphorisme met l'accent sur l'importance de créer un code élégant et conforme aux principes de Python.

Le fragment de code ci-dessous montre une approche qui pourrait être améliorée :

def square(num):
    squares = []
    for i in range(num):
        squares.append(i*i)
    return squares

Cette fonction:

  • Crée initialement une liste vide.
  • Comporte une boucle qui ajoute des éléments à la fin de la liste.
  • Finalement, retourne la liste.

Bien que ce code soit fonctionnellement correct, il n'est pas idéal d'un point de vue Pythonique, et il pourrait être plus difficile à maintenir.

Il est possible de l'écrire de manière beaucoup plus élégante en utilisant des générateurs. Voici la fonction génératrice équivalente à la fonction précédente :

def square(num):
    for i in range(num):
        yield i*i

Mieux encore, vous pouvez utiliser l'expression de compréhension de générateur suivante :

num = ...
squares = (i*i for i in range(num))

L'explicite est préférable à l'implicite.

Lorsque vous écrivez du code, ne laissez pas les autres développeurs ou utilisateurs deviner le comportement implicite ou par défaut de votre code. Soyez précis. Considérez l'exemple des importations globales :

from some_module import * # importation globale
from some_other_module import *

result = some_function() # d'où vient cette fonction ?

Évitez d'utiliser des importations globales autant que possible, car elles manquent de clarté et peuvent être inefficaces. Soyez précis lorsque vous importez des fonctions et des classes à partir d'autres modules :

from some_module import this_function # importation explicite

result = this_function() # nous savons maintenant d'où elle vient.

La simplicité est préférable à la complexité.

Cet aphorisme nous encourage à maintenir la simplicité de notre code et à éviter toute complexité superflue. Par exemple, si vous souhaitez inverser une chaîne, vous pourriez être tenté d'implémenter la solution récursive suivante :

def reverse_string(my_string):
  if my_string == "":
    return my_string
  else:
    return reverse_string(my_string[1:]) + my_string[:1]

Bien que cette méthode fonctionne, elle est probablement trop élaborée pour ce problème, étant donné qu'il existe des manières plus directes et plus "Pythonic" de le faire.

Voici l'approche utilisant le découpage de chaînes :

>>> rev_string = my_string[::-1]
>>> rev_string
'nohtyP'

Et voici une approche utilisant les fonctions et méthodes intégrées :

>>> rev_string = ''.join(reversed(my_string))
>>> rev_string
'nohtyP'

Le complexe est préférable au compliqué.

Alors, quelle est la signification de ce prochain aphorisme du Zen de Python ?

L'inversion de chaînes en Python est une opération très simple. Cependant, dans des cas concrets, nous pouvons avoir besoin d'une logique plus complexe. Voici un exemple relativement simple :

Imaginez que vous ayez besoin de vous connecter à une base de données :

  • Vous devez d'abord analyser un fichier de configuration TOML pour obtenir les informations de connexion à la base de données.
  • Le connecteur de base de données doit être installé.
  • Vous pouvez ensuite définir une fonction pour établir la connexion, anticiper les erreurs de connexion, mettre en œuvre la gestion des erreurs et bien plus encore.
  • Enfin, après vous être connecté à la base de données, vous pouvez exécuter des requêtes.

Bien que cette procédure soit relativement simple, elle nécessite une logique plus complexe que l'inversion de chaînes. Mais cela ne signifie pas qu'elle doive être compliquée. Vous pouvez toujours utiliser efficacement les fonctionnalités des modules intégrés et organiser votre code de manière à ce qu'il soit lisible, compréhensible et que d'autres développeurs puissent y contribuer.

Le plat est préférable à l'imbriqué.

Une structure plate est plus facile à analyser et à comprendre qu'une structure imbriquée. Lorsque vous travaillez sur un projet, vous pourriez être tenté d'isoler les fonctionnalités en créant des modules distincts. Cependant, une granularité excessive peut devenir contre-productive.

Ceci étant dit, il est parfois nécessaire de dépasser la structure plate. Mais même si vous avez besoin d'imbrication, limitez-la au minimum.

Voici un exemple :

from db_info.config.actions.parse.parse_config import parse_toml # trop difficile à déchiffrer !
...

from db_config.parse_config import parse_toml # beaucoup mieux !
...

Le clairsemé est préférable au dense.

Si vous êtes un développeur novice, vous pourriez être tenté d'abuser de certaines des fonctionnalités du langage. Les compréhensions de listes, par exemple, sont considérées comme "Pythonic", mais leur utilisation doit être réservée aux situations où elles sont réellement justifiées.

Considérez l'exemple de compréhension de liste suivant :

prices_dict = {'melons':40,'apples':70,'berries':55}
items = [(fruit,price) for fruit in prices_dict.keys() if fruit.startswith('m') for price in prices_dict.values() if price < 50]
print(items)
# Résultat : [('melons', 40)]

Cette compréhension de liste est trop dense et difficile à interpréter. Dans ce cas, une boucle for équivalente avec des conditions serait plus lisible. Cela indique que la compréhension est difficile à saisir. 🙂

La lisibilité compte.

Vous devez toujours écrire du code lisible. Voici quelques suggestions simples pour améliorer la lisibilité de votre code :

  • Utiliser des noms de variables descriptifs.
  • Ajouter des docstrings pour les fonctions et les classes.
  • Commenter le code lorsque cela est nécessaire.
  • Ajouter des annotations de type pour les arguments et les valeurs de retour des fonctions.

Les cas spéciaux ne sont pas suffisamment spéciaux pour enfreindre les règles.

Dans la mesure du possible, vous devez adhérer aux règles du langage et aux bonnes pratiques recommandées.

Mais cela est-il toujours possible ? Non, et c'est pourquoi nous avons l'aphorisme suivant.

Bien que l'aspect pratique l'emporte sur la pureté.

C'est la suite logique de l'aphorisme précédent. Bien qu'il soit recommandé de respecter les règles du langage, il est parfois tout à fait acceptable de déroger à certains principes.

Les erreurs ne doivent jamais passer silencieusement.

En Python, les erreurs d'exécution sont assez fréquentes. Par bonne pratique, vous devez toujours gérer les erreurs et ne pas simplement les ignorer.

Vous pouvez anticiper et mettre en œuvre une gestion appropriée des erreurs, en fonction de différents types d'erreurs :

try:  
    # effectuer cette action
except ErrorType1:
    # faire ceci
except ErrorType2:
    # faire autre chose
...

Il est préférable d'éviter les exceptions nues et génériques. Les versions plus récentes de Python (à partir de Python 3.11) prennent en charge le chaînage d'exceptions et les groupes d'exceptions, ce qui permet une gestion des exceptions plus sophistiquée.

À moins qu'elles ne soient explicitement ignorées.

Ceci fait suite à l'aphorisme précédent. Si la conception nécessite ou permet que l'erreur soit ignorée, cela doit être fait de manière explicite.

Par exemple, lors de la connexion à une base de données, vous pouvez rencontrer une erreur `OperationalError` en raison d'informations de configuration invalides. Dans ce cas, essayez de vous connecter en utilisant une configuration personnalisée. Si une erreur opérationnelle se produit, utilisez la configuration par défaut et tentez de vous connecter à la base de données.

try:
   # connexion en utilisant une configuration personnalisée
except OperationalError:
   # connexion en utilisant la configuration par défaut

Face à l'ambiguïté, refusez la tentation de deviner.

Cet aphorisme du Zen de Python est très clair. En cas de doute, ne devinez pas. Exécutez plutôt votre code et vérifiez le résultat. Ensuite, selon que le comportement est celui souhaité, améliorez la lisibilité ou modifiez la logique si nécessaire.

Considérez l'exemple simple suivant avec un tuple de booléens :

>>> True, True == (True, True)
(True, False)
>>> True, (True == (True, True))
(True, False)
>>> (True, True) == (True, True)
True

Il devrait y avoir une – et de préférence une seule – façon évidente de le faire.

Pour effectuer une tâche donnée, il devrait exister une seule manière recommandée et "Pythonic" de le faire. Cependant, pour tout problème, il peut y avoir plusieurs solutions.

Même dans l'exemple simple d'inversion de chaîne, nous avons examiné une solution récursive, le découpage de chaîne et la méthode `join()`.

C'est aussi une blague en interne, compte tenu de l'utilisation incohérente des tirets. Nous utilisons généralement des tirets cadratins sans espaces de début et de fin, ou avec des espaces de début et de fin.

Voici donc ce que nous pouvons déduire. L'aphorisme qui insiste sur le fait qu'il devrait y avoir une – et une seule – manière "Pythonic" de faire les choses, peut lui-même être écrit de plus de deux manières.

Bien que cela puisse ne pas être évident au début, sauf si vous êtes néerlandais.

Écrit sur un ton léger, cet aphorisme fait référence à Guido Van Rossum, le créateur de Python (qui est néerlandais). La manière "Pythonic" d'accomplir une tâche est plus intuitive pour ceux qui ont créé le langage.

Ainsi, pour les développeurs, il faut de l'expérience - et apprendre de cette expérience - pour mieux tirer parti des fonctionnalités du langage.

Mieux vaut maintenant que jamais.

Comme c'est le cas pour plusieurs autres aphorismes du Zen de Python, celui-ci peut être interprété de plusieurs manières.

Une interprétation est que, en tant que développeur, il est fréquent de procrastiner pour commencer à coder un projet. Plutôt que d'attendre de planifier chaque détail du projet, commencer maintenant est une meilleure idée.

Une autre interprétation possible est la suivante : un code qui s'exécute en un nombre fini d'étapes (et se termine) est souvent préférable à un code comportant des bogues et bloqué dans une boucle infinie.

Bien que jamais soit souvent préférable à *tout de suite*.

Cet aphorisme semble contredire le précédent. Bien qu'il soit préférable de ne pas tergiverser, nous devons quand même réfléchir au problème et concevoir le code en conséquence.

Coder un module - sans y réfléchir correctement - rempli de mauvaises pratiques et d'anti-modèles est une mauvaise idée. En effet, un tel code est difficile à refactoriser et à corriger.

Si l'implémentation est difficile à expliquer, c'est une mauvaise idée.

Toute logique, aussi complexe soit-elle, peut toujours être implémentée d'une manière simple à expliquer et facile à comprendre.

Si l'implémentation est difficile à expliquer, il y a probablement une complexité superflue. Le code peut être modifié ou refactorisé de manière à le rendre plus facile à suivre.

Si l'implémentation est facile à expliquer, cela peut être une bonne idée.

Cet aphorisme est lié au précédent et est également intuitif. Si l'implémentation peut être expliquée simplement, c'est probablement une bonne idée.

En effet, un code dont l'implémentation peut être décrite en termes simples a de fortes chances d'être lisible et facile à suivre, avec un minimum de complexité.

Les espaces de noms sont une excellente idée – utilisons-en davantage !

En Python, les objets dans une portée spécifique sont accessibles en utilisant leurs noms dans leur espace de noms. Par exemple, vous pouvez créer une classe et l'utiliser comme modèle pour créer des instances de la classe. Les variables d'instance se trouveront toutes dans l'espace de noms de l'instance.

Cela nous permet d'utiliser des objets portant le même nom, sans conflit, car ils se trouvent dans des espaces de noms différents. Toutefois, vous ne devez les utiliser que si cela est nécessaire et vous assurer que la simplicité et la lisibilité du code ne sont pas compromises.

Conclusion

Voilà qui conclut ce tutoriel ! J'espère que ce guide vous a permis de comprendre comment le Zen de Python met en évidence l'importance du style de code et des bonnes pratiques de codage en Python. Plus vous codez, plus vous vous améliorerez.

Si vous souhaitez apprendre à écrire du code concis et lisible, je vous invite à lire cet article sur les expressions Python sur une seule ligne.

Auteur
France

Rédacteur tech, guides pratiques et astuces numériques.