Python Enhancement Proposal : les bonnes pratiques de code en Python D. Arrivault1 1 Laboratoire d’Excellence Archimède Aix Marseille Université 11 avril 2014 D. Arrivault (AMU) Mets du PEP! 11 avril 2014 1 / 47 Outline 1 C’est quoi PEP ? 2 La philosophie du Zen : PEP 20 3 Du concret : PEP 8 4 Les Docstring : PEP 257 D. Arrivault (AMU) Mets du PEP! 11 avril 2014 2 / 47 Outline 1 C’est quoi PEP ? 2 La philosophie du Zen : PEP 20 3 Du concret : PEP 8 4 Les Docstring : PEP 257 D. Arrivault (AMU) Mets du PEP! 11 avril 2014 3 / 47 C’est quoi PEP ? D. Arrivault (AMU) Mets du PEP! 11 avril 2014 4 / 47 PEP un document pour fournir des infos à la communauté Python pour décrire des nouvelles fonctionnalités Python ... officiel Revue, discutée, approuvée, intégrée ... ou rejetée par la communauté. D. Arrivault (AMU) Mets du PEP! 11 avril 2014 5 / 47 Les types Trois types de PEP Standards Track PEP : nouvelles fonctionnalités. Informational PEP : problèmes de design, guides, infos. Process PEP : comme les Standards Tracks mais pour tout ce qui n’est pas du code. Au programme PEP 20 (Informational) : The Zen of Python PEP 8 (Process) : Style Guide for Python Code PEP 257 (Informational) : Docstring Conventions D. Arrivault (AMU) Mets du PEP! 11 avril 2014 6 / 47 Outline 1 C’est quoi PEP ? 2 La philosophie du Zen : PEP 20 3 Du concret : PEP 8 4 Les Docstring : PEP 257 D. Arrivault (AMU) Mets du PEP! 11 avril 2014 7 / 47 La philosophie du Zen : PEP 20 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. D. Arrivault (AMU) Mets du PEP! 11 avril 2014 8 / 47 La philosophie du Zen : PEP 20 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. D. Arrivault (AMU) Mets du PEP! 11 avril 2014 9 / 47 Outline 1 C’est quoi PEP ? 2 La philosophie du Zen : PEP 20 3 Du concret : PEP 8 4 Les Docstring : PEP 257 D. Arrivault (AMU) Mets du PEP! 11 avril 2014 10 / 47 Du concret : PEP 8 D. Arrivault (AMU) Mets du PEP! 11 avril 2014 11 / 47 Ce qu’on y trouve. Disposition du code Espaces dans les expressions Commentaires Compatibilité des versions Conventions de nommage Recommandations de programmation Avec une mise en garde : A style guide is about consistency. Consistency with this style guide is important. Consistency within a project is more important. Consistency within one module or function is most important. But most importantly : know when to be inconsistent – sometimes the style guide just doesn’t apply. When in doubt, use your best judgment. Look at other examples and decide what looks best. And don’t hesitate to ask ! D. Arrivault (AMU) Mets du PEP! 11 avril 2014 12 / 47 Installation. > sudo pip install pep8 > sudo pip install --upgrade pep8 Si on n’a pas ”pip” : > sudo easy_install pep8 Si on est sous Ubuntu/Debian > sudo apt-get install pep8 Puis on vérifie son code avec : > pep8 myscript.py où pylint... D. Arrivault (AMU) Mets du PEP! 11 avril 2014 13 / 47 Disposition du code D. Arrivault (AMU) Mets du PEP! 11 avril 2014 14 / 47 Disposition du code Indentation : 4 espaces, éviter les tabulations. 80 (79 sans le retour chariot) caractères max par ligne (72 pour les textes de commentaires). On ne coupe pas une ligne n’importe où (après un opérateur pas avant). 80 caractères ⇒ limiter la complexité. D. Arrivault (AMU) Mets du PEP! 11 avril 2014 15 / 47 Disposition du code class Rectangle(Blob): def __init__(self, width, height, color=’black’, emphasis=None, highlight=0): if (width == 0 and height == 0 and color == ’red’ and emphasis == ’strong’ or highlight > 100): raise ValueError("sorry, you lose") if width == 0 and height == 0 and (color == ’red’ or emphasis is None): raise ValueError("I don’t think so -- values are %s, %s" % (width, height)) Blob.__init__(self, width, height, color, emphasis, highlight) D. Arrivault (AMU) Mets du PEP! 11 avril 2014 16 / 47 Disposition du code Espacements : Deux lignes vides entre éléments ’top-niveau’ (classes) Une ligne entre les éléments ’internes’ (méthodes) Encodage : #!/usr/bin/env python #−∗− coding: utf−8 −∗− Python core ⇒ Latin-1 Python 3.x ⇒ utf-8 D. Arrivault (AMU) Mets du PEP! 11 avril 2014 17 / 47 Disposition du code Import au début du script ; après les commentaires / docstrings un modules doit être importé sur une ligne différente sauf en cas de hiérarchie. Non : import os, sys Oui : import os import sys from subprocess import Popen, PIPE D. Arrivault (AMU) Mets du PEP! 11 avril 2014 18 / 47 Disposition du code Import Import absolu à privilégier : from mypkg import sibling Pas d’import générique de la forme from mypkg import * Pour l’import de classe intra-module : from myclass import MyClass from foo.bar.yourclass import YourClass En cas de conflit, alors on peut faire : import myclass import foo.bar.yourclass my_object = myclass.MyClass() your_object = foo.bar.yourclass.YourClass() D. Arrivault (AMU) Mets du PEP! 11 avril 2014 19 / 47 Disposition du code Ordre des Import 1 Bibliothèque standard 2 Bibliothèque(s) tierce(s) 3 Mes bibliothèques locales 4 Une ligne blanche entre chaque groupe d’import. D. Arrivault (AMU) Mets du PEP! 11 avril 2014 20 / 47 Disposition du code #!/usr/bin/env python # −∗− coding: utf−8 −∗− # Copyright 2010 Bruno Bord # # Licensed under the WTFPL, Version 2 # DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE # TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION # 0. You just DO WHAT THE FUCK YOU WANT TO. ”””A very simple XMPP bot. This bot responds to simple commands. You may want to send a ”help” message in order to get the list of the available commands. ””” import logging import os import xmpp from xmpp.protocol import Message from xmppbot import Bot, ConnectionError D. Arrivault (AMU) Mets du PEP! 11 avril 2014 21 / 47 Espaces dans les expressions Éviter les espaces superflus Pas d’espace dans les parenthèses, crochets ou accolades, avant une virgule, un point-virgule, deux points, avant une parenthèse ouvrante commençant une liste d’arguments de fonctions, avant un crochet ouvrant sur une indexation. Des espaces autour des opérateurs. D. Arrivault (AMU) Mets du PEP! 11 avril 2014 22 / 47 Espaces dans les expressions Non : Oui : spam( ham[ 1 ], { eggs: 2 } ) if x == 4 : print( x , y ) ; x , y = y , x spam (1) dict [’key’] = list [index] x = 1 y = 2 long_variable = 3 spam(ham[1], {eggs: 2}) if x == 4: print(x, y) x, y = y, x spam(1) dict[’key’] = list[index] x = 1 y = 2 long_variable = 3 x = x * 2 - 1 def complex(real, imag = 0.0): return magic(r = real, i = imag) x = x*2 - 1 def complex(real, imag=0.0): return magic(r=real, i=imag) D. Arrivault (AMU) Mets du PEP! 11 avril 2014 23 / 47 Commentaires D. Arrivault (AMU) Mets du PEP! 11 avril 2014 24 / 47 Commentaires De manière générale : des commentaires qui contredisent le code sont pires que pas de commentaire ; garder les commentaires à jour quand le code change ; faire des phrases ... complètes ; en anglais. D. Arrivault (AMU) Mets du PEP! 11 avril 2014 25 / 47 Commentaires Pour les blocs s’appliquent sur le code qui suit ; chaque ligne commence par un ”#” suivi d’un espace ; les paragraphes sont séparés d’une ligne vide commençant par un ”#”. Pour les commentaires de ligne séparés par deux espaces après le code ; commencent par un ”#” suivi d’un espace ; doivent se justifier, éviter d’enfoncer des portes ouvertes ! D. Arrivault (AMU) Mets du PEP! 11 avril 2014 26 / 47 Commentaires # Python comment exemple. x = x + 1 # x incrementing # Bad! x = x + 1 # add a margin # Better. D. Arrivault (AMU) Mets du PEP! 11 avril 2014 27 / 47 Compatibilité des versions Comme on utilise obligatoirement un gestionnaire de version Git, SVN ou autre (ou alors c’est mal !), dans le code il convient de tenir à jour les versions de commit : __version__ = "$Revision: 380301e300a6 $" # $Source$ à mettre après le docstring du module. D. Arrivault (AMU) Mets du PEP! 11 avril 2014 28 / 47 Conventions de nommage D. Arrivault (AMU) Mets du PEP! 11 avril 2014 29 / 47 Conventions de nommage Principe général : les noms reflètent l’usage plutôt que l’implémentation. Styles existants distinctifs b (une seule minuscule) B (une seule majuscule) minuscules MAJUSCULES minuscules avec des underscores MAJUSCULES AVEC DES UNDERSCORES MotsEnMajuscule (appelé souvent CamelCase) motAvecCapitalisationMelangee (minuscule au premier mot) Mots En Majuscule Avec Des Underscores (Moche !) D. Arrivault (AMU) Mets du PEP! 11 avril 2014 30 / 47 Conventions de nommage Modules nom court, tout en minuscules, underscores si nécessaire Paquetages nom court, tout en minuscules, underscore très déconseillé D. Arrivault (AMU) Mets du PEP! 11 avril 2014 31 / 47 Conventions de nommage Conventions prescrites classes : CorrectClassName exceptions : IncorrectClassNameError (suffixe ”Error” !) fonctions : get_correct_number() méthodes : get_correct_number(self) arguments des méthodes et fonctions : get_correct_number(random=False) variables : number = my_object.get_correct_number() constantes : ANSWER_TO_LIFE_UNIVERSE = 42 Conventions proscrites Ne jamais utiliser les caractères ’l’, ’O’ ou ’I’ comme nom de variable. Avec certaines fontes elles se confondent avec 0 ou 1. D. Arrivault (AMU) Mets du PEP! 11 avril 2014 32 / 47 Conventions de nommage Underscore de début et de fin 1 au début : _ma_variable_interne 1 à la fin : ma_variable_en_conflit_avec_une_variable_python_ 2 au début : __mon_attribut_de_classe 2 au début et à la fin = Interdit ! !. Objets magiques de Python : __init__, __import__, __file__... Obligatoire Tous les modules doivent déclarer les noms des objets publiques à l’aide de l’attribut __all__. D. Arrivault (AMU) Mets du PEP! 11 avril 2014 33 / 47 Recommandations de programmation De l’utilisation des implémentations de Python L’utilisation de PyPy, Jython, IronPython, Cython, Psyco (...) doit se faire de manière efficiente : S’assurer de la pérennité du code, Vérifier la performance. ex : la concaténation de string doit se faire avec la fonction .join() et non par l’addition a += b de CPython qui n’est pas toujours optimale et absente des implémentations sans refcounting. D. Arrivault (AMU) Mets du PEP! 11 avril 2014 34 / 47 Recommandations de programmation Comparaison de singletons Ne pas utiliser if x: mais if x is not None:. Cas spécial : les sequences (strings, lists, tuples) Ne pas utiliser if not leng(seq): mais if not seq: qui est plus rapide. Cas spécial : les booléens Ne pas utiliser if my_bool == True: ou bien pire encore if my_bool is True: mais if my_bool:. D. Arrivault (AMU) Mets du PEP! 11 avril 2014 35 / 47 Recommandations de programmation Les exceptions Non : class MessageError(Exception): pass raise MessageError, "Ouch! Here is my message!" Oui : class MessageError(Exception): ”””Base class for errors in the email package.””” pass raise MessageError("Ouch! Here is my message!") D. Arrivault (AMU) Mets du PEP! 11 avril 2014 36 / 47 Recommandations de programmation Le ”catch” doit être si possible spécifique et ne comporter que le code strictement nécessaire (pas de commentaire !) try: value = collection[key] except KeyError: return key_not_found(key) else: return handle_value(value) D. Arrivault (AMU) Mets du PEP! 11 avril 2014 37 / 47 Recommandations de programmation Les chaı̂nes de caractères Utiliser les méthodes de chaı̂ne plutôt que le module string. Utiliser endswith ou startswith plutôt que le découpage des chaı̂nes if foo.startswith(’bar’): print "good" if foo[:3] == ’bar’: print "not good" D. Arrivault (AMU) Mets du PEP! 11 avril 2014 38 / 47 Outline 1 C’est quoi PEP ? 2 La philosophie du Zen : PEP 20 3 Du concret : PEP 8 4 Les Docstring : PEP 257 D. Arrivault (AMU) Mets du PEP! 11 avril 2014 39 / 47 Les Docstring : PEP 257 D. Arrivault (AMU) Mets du PEP! 11 avril 2014 40 / 47 Quest-ce que Docstring ? A docstring is a string literal that occurs as the first statement in a module, function, class, or method definition. Such a docstring becomes the __doc__ special attribute of that object. D. Arrivault (AMU) Mets du PEP! 11 avril 2014 41 / 47 Où ? D. Arrivault (AMU) Mets du PEP! 11 avril 2014 42 / 47 Où ? Partout ! D. Arrivault (AMU) Mets du PEP! 11 avril 2014 42 / 47 Où ? Obligatoires dans : tous les modules publics toutes les fonctions toutes les classes toutes les méthodes de ces classes Non nécessaires dans : les méthodes non publiques où elles peuvent êtres remplacées par un simple commentaire après la ligne def. D. Arrivault (AMU) Mets du PEP! 11 avril 2014 43 / 47 Comment ? Propriétés Utiliser les """trois guillemets anglais""". Si le docstring contient des backslashes, utiliser la syntaxe r"""mon docstring avec \""". Docstring sur une ligne Pour préciser l’effet d’une fonction ou méthode. Elle doit commencer par ”Do this” ou ”Return that”. Pas de description. Elle ne fait qu’une ligne ! def kos_root(): ”””Return the pathname of the KOS root directory .””” global _kos_root if _kos_root: return _kos_root ... D. Arrivault (AMU) Mets du PEP! 11 avril 2014 44 / 47 Comment ? Docstring sur plusieurs lignes Elle commence par une ligne simple contenant une précision (comme pour le Docstring sur une ligne). Puis il faut une ligne blanche. La suite résume précisément les différentes i/o et/ou l’usage. def complex(real=0.0, imag=0.0): ”””Form a complex number. Keyword arguments: real −− the real part ( default 0.0) imag −− the imaginary part ( default 0.0) ””” if imag == 0.0 and real == 0.0: return complex_zero ... D. Arrivault (AMU) Mets du PEP! 11 avril 2014 45 / 47 Merci Merci. D. Arrivault (AMU) Mets du PEP! 11 avril 2014 46 / 47 Crédits Cette présentation est librement inspirée de pep8-talk sous contrat Creative Commens CC-BY-SA. Les images : Geek and Poke (Creative Commons) Abstruse Goose (Creative Commons) Camel Case (Creative Commons) Sphinx : David Holt (Creative Commons) D. Arrivault (AMU) Mets du PEP! 11 avril 2014 47 / 47