Tout commence par la fameuse PEP20, The Zen of Python, écrite par Tim Peters, et qui exprime les valeurs du langage.
Celle-ci énonce les règles suivant un poème. On peut la retrouver via l'instruction import this
dans un interpréteur Python.
Le beau est préférable au laid.
Le point de départ. Un bon code Python se doit d'être beau, c'est à dire agréable à regarder. Nous reviendrons par la suite sur les règles de style, qui définissent plus précisément en quoi consiste un beau code.
Cela se voit en Python par l'utilisation de mots plutôt que de symboles pour certains opérateurs (and
, or
, not
, in
), qui rendent les expressions plus proches du langage naturel.
if number > 0 and number not in invalid_numbers:
...
L'explicite est préférable à l'implicite.
Un développeur doit pouvoir lire un code Python sans se demander sans cesse ce que fait telle ou telle ligne. Utiliser des noms et des constructions explicites permet de limiter ce genre de problèmes.
Par exemple, en programmation objet, lors d'un héritage et de la surcharge de la méthode d'initialisation (__init__
), il convient d'appeler explicitement la méthode de la classe parente.
Cela ne sera jamais fait automatiquement dans le dos du développeur, afin d'avoir la main sur le comportement voulu.
class User:
def __init__(self, name):
self.name = name
class SecureUser(User):
def __init__(self, name, password):
super().__init__(name)
self.password = password
Le simple est préférable au complexe.
Certaines structures du langage vont s'avérer plus complexes que d'autres. L'application d'un décorateur est une instruction complexe, par les mécanismes qu'elle met en œuvre : patron de conception décorateur, fonctions passées implicitement en paramètre.
@staticmethod
def method():
...
Le complexe est préférable au compliqué.
Il convient déjà de bien faire la différence entre les deux termes.
« compliqué » se rapporte à l'utilisation. Un code compliqué est difficile à relire et à maintenir. Un code complexe utilise des mécanismes avancés, mais il peut être simple à appréhender. Pour reprendre l'exemple précédent, l'application d'un décorateur n'est pas compliquée.
Le plat est préférable à l'imbriqué.
Quand on lit un code, il est facile de perdre le fil et d'oublier à quel endroit on se trouve. D'autant plus si de nombreux niveaux d'imbrications se succèdent.
Pour palier à ce problème, on préférera produire du code plat chaque fois que cela est possible, et ainsi éviter les imbrications inutile. Dans le cadre d'une fonction, on choisira par exemple de retourner directement quand des préconditions ne sont pas validées, plutôt que de placer le contenu de notre fonction dans plusieurs sous-niveaux de conditions.
def print_items(obj):
if not hasattr(obj, 'items'):
return
for item in obj.items:
print(item)
L'aéré est préférable au dense.
Un code compréhensible est un code aéré. La syntaxe même du langage se base sur l'indentation pour séparer les blocs logiques. L'aération du code y est donc une valeur très importante.
La lisibilité compte.
Vous, et les autres développeurs du projet, passerez probablement plus de temps à lire votre code qu'à l'écrire. Le code se doit donc d'être lisible facilement, pour ne pas faire perdre de temps à tous.
La lisibilité passera par de nombreux points évoqués par les autres directives, mais aussi par un choix judicieux des noms de fonctions et variables par exemple.
def reset_password(*users, password=''):
for user in users:
user.password = password
Les cas spéciaux ne le sont pas assez pour briser les règles.
Ce principe est celui de la cohérence. Les mêmes règles s'appliquent pour tous, ce n'est pas parce qu'un bout de code semble sortir du lot qu'il y déroge. Même un code imbriqué doit rester lisible, par exemple.
Bien que la praticité prévale sur la pureté.
Et cette règle, qui nuance la précédente, représente le bon sens. Il peut devenir nécessaire d'outrepasser les règles pour des raisons pratiques, telles que des questions de performances. Cela doit dans tous les cas rester anecdotique.
Les erreurs ne devraient jamais se produire silencieusement.
Quand une erreur se produit c'est qu'il y a un problème, quel qu'il soit. Ce problème ne doit jamais être masqué au développeur.
>>> def division(a, b):
... return a / b
...
>>> division(1, 0)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in division
ZeroDivisionError: division by zero
À moins d'être explicitement tues.
Le développeur peut ensuite choisir d'ignorer une erreur en particulier, car celle-ci est attendue dans ce cas précis.
Mais il le fera de façon explicite, avec un bloc try
/except
par exemple.
def division(a, b):
try:
return a / b
except ZeroDivisionError:
return float('nan')
En cas d'ambiguïté, résister à la tentation de deviner.
Deviner implique un choix, choix qui ne sera pas forcément clair pour tous les développeurs. S'il n'est pas clair, c'est qu'il n'est pas explicite.
Par exemple, dans le cas d'une addition entre de valeurs de types str
et int
, il y a ambiguïté entre le fait de choisir de convertir les deux opérandes en nombres ou en chaînes de caractères.
Aucune conversion implicite ne sera effectuée, il faudra convertir manuellement les deux opérandes en types compatibles.
>>> a = '5'
>>> a + 1
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: Can´t convert 'int' object to str implicitly
>>> int(a) + 1
6
>>> a + str(1)
'51'
Il devrait y avoir une -- et de préférence une seule -- manière évidente de le faire.
Python prône le fait qu'il existe toujours une manière optimale de procéder, et donc que toutes ne se valent pas. Celle-ci est préférable car évidente.
Nous y reviendrons plus loin avec les mécanismes du langage, mais la manière évidente d'itérer sur des nombres est par exemple d'utiliser une boucle for
.
for i in range(100):
print(apply_func(i))
Bien que cette manière ne vous semble pas évidente au premier abord, à moins que vous ne soyez néerlandais.
Cependant, l'évidence n'est pas innée. Elle vient avec la pratique, et est entre autres dictée par cette PEP. La manière évidente est la manière la plus idiomatique.
Cette règle se termine par une note humoristique sur Guido van Rossum, néerlandais, le créateur de Python.
Maintenant est préférable à jamais.
La procrastination est l'ennemie du développeur Python. Si vous avez besoin d'une fonctionnalité manquante, implémentez-la, ne codez pas de rustines temporaires pour y revenir « plus tard ».
Bien que jamais soit souvent préférable à tout de suite.
Assurez-vous cependant que cette fonctionnalité soit vraiment nécessaire. Dans le cas contraire, il peut être préférable de ne pas perdre trop de temps dessus pour le moment.
Ce point sera détaillé par la suite quand nous aborderons le principe YAGNI.
Si l'implémentation est difficile à expliquer, c'est une mauvaise idée.
Une implémentation difficile à expliquer est compliquée, elle produira du code compliqué. On préférera donc l'éviter au profit d'une implémentation plus simple, plus facile à expliquer.
Si l'implémentation est facile à expliquer, il peut s'agir d'une bonne idée.
Pour autant, être facile à expliquer n'en fait pas une bonne implémentation. C'est une bonne chose, mais ce n'est pas un critère suffisant.
Il est facile d'expliquer comment concaténer plusieurs chaînes de caractères : on itère sur notre ensemble de chaînes, et on les concatène chacune à une chaîne finale à l'aide de l'opérateur +
.
Pourtant, celle solution est à proscrire, dû à l'inefficacité de l'opérateur de concaténation, et à la présence d'une méthode join
bien plus lisible.
>>> tags = ['<html>', '<body>', '<p>', 'text', '</p>', '</body>', '</html>']
>>> ''.join(tags)
'<html><body><p>text</p></body></html>'
Les espaces de noms sont une sacrée bonne idée -- utilisons-les plus souvent !
Les espaces de noms sont créés à l'aide des paquets, modules et objets, ils permettent de diviser les classes et fonctions en ensembles logiques. Ils évitent aussi les conflits de noms, un même nom pouvant être utilisé pour des valeurs différentes dans des espaces différents. On aimera alors en user pour bien classifier nos objets.
>>> import math, cmath
>>> math.exp(0)
1.0
>>> cmath.exp(0)
(1+0j)
Tim Peters avait initialement annoncé que son Zen of Python contiendrait 20 directives. Si vous y avez prêté attention, on en compte plutôt 19. Où est passée cette fameuse 20ème règle ?
Certains évoquent qu'elle pourrait être implicite, une simple ligne vide. Une ligne vide qui rappellerait l'aération.