Python Enhancement Proposal : les bonnes pratiques de code en

publicité
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
Téléchargement