Les 10 commandements de la PEP8

PEP?

  • Python Extension Proposal
  • Revue, discutée, approuvée, intégrée
  • ... ou rejetée

PEP

PEP8

  • Homogénéïté de la bibliothèque standard
  • Lisibilité
  • Bonne pratique qui se propage
  • "ne pas me faire réfléchir"

PEP8: Si tu ne le fais pas pour les autres, fais-le pour toi

Autrement dit : "sois poli"

PEP 20

"beautiful is better than ugly"

"readability counts"

"in the face of ambiguity, refuse the temptation to guess"

"there should be one-- and preferably only one --obvious way to do it"

PEP8

  • Code layout
  • Imports
  • Whitespace in expressions and statements
  • Comments
  • Documentation strings
  • Version bookkeeping
  • Naming conventions
  • Programming recommendations

[SPOILER ALERT!!!]

Spoiler

1 $ sudo pip install pep8
2 $ sudo pip install --upgrade pep8

Si on n'a pas "pip"

1 $ sudo easy_install pep8

Si on est sous Ubuntu/Debian

1 $ sudo apt-get install pep8

Spoiler

1 $ pep8 optparse.py
2 optparse.py:69:11: E401 multiple imports on one line
3 optparse.py:77:1: E302 expected 2 blank lines, found 1
4 optparse.py:88:5: E301 expected 1 blank line, found 0
5 optparse.py:222:34: W602 deprecated form of raising exception
6 optparse.py:347:31: E211 whitespace before '('
7 optparse.py:357:17: E201 whitespace after '{'
8 optparse.py:472:29: E221 multiple spaces before operator
9 optparse.py:544:21: W601 .has_key() is deprecated, use 'in'

Spoiler encore plus méchant

pylint

Retour à la PEP8

Code layout

L'indentation, bon sang!

Indentation : 4 espaces

Tabulations ?

Tabulations c'est "ok"

... mais :

  • ne pas mixer les tabulations et les espaces
  • privilégier les espaces, quand même.

Pourquoi ?

Indentation

  • huit espaces, c'est trop (8x1, 8x2, 8x3, 8x4...)
  • deux, c'est trop peu
  • un, on pourrait...

*COUGH*

Code layout

Lignes

  • Limite : 80 caractères - enfin 79...
  • Retours chariots pas n'importe où, quand même...

Code Layout

Lignes

  • Limite : 80 caractères
  • Indentation de 4 espaces

... tu vois le rapport ?

Code layout

Lignes

 1 class Rectangle(Blob):
 2 
 3     def __init__(self, width, height,
 4                  color='black', emphasis=None, highlight=0):
 5         if width == 0 and height == 0 and \
 6            color == 'red' and emphasis == 'strong' or \
 7            highlight > 100:
 8             raise ValueError("sorry, you lose")
 9         if width == 0 and height == 0 and (color == 'red' or
10                                            emphasis is None):
11             raise ValueError("I don't think so -- values are %s, %s" %
12                              (width, height))
13         Blob.__init__(self, width, height,
14                       color, emphasis, highlight)

Code layout

Espacements

  • Deux lignes vides entre éléments 'top-niveau' (classes)
  • Une ligne entre les éléments 'internes' (méthodes)

Pourquoi ?

Espacement == Ergonomie

Code Layout

Encodage

1 #!/usr/bin/env python
2 #-*- coding: utf-8 -*-

... mais on peut utiliser Latin-1, ou win-1252 ou... nawak.

Code Layout

Encodage

  • Python core => Latin-1
  • Python 3.x => utf-8

Code Layout

Encodage

  • noms de variables,
  • de fonctions,
  • de constantes,
  • de méthodes,
  • de propriétés,
  • de classes...

EN ASCII UNIQUEMENT !

Imports

Imports

  • Au début du script
  • Après les commentaires / docstrings

Imports

NON

1 import sys, os

Imports

ÇA C'EST OUI

1 import sys
2 import os

Imports

AH OUI ÇA OUI ÇA AUSSI

1 from subprocess import Popen, PIPE

Imports

Ordre

  1. Bibliothèque Standard
  2. Bibliothèque(s) tierce(s)
  3. Imports locaux / spécifiques

... et une ligne blanche entre les groupes d'import

Imports

 1 #!/usr/bin/env python
 2 # -*- coding: utf-8 -*-
 3 #  Copyright 2010 Bruno Bord
 4 #
 5 #  Licensed under the WTFPL, Version 2
 6 #            DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 
 7 # TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 
 8 # 0. You just DO WHAT THE FUCK YOU WANT TO.
 9 
10 """A very simple XMPP bot.
11 
12 This bot responds to simple commands. You may want to send a "help"
13 message in order to get the list of the available commands.
14 
15 """
16 
17 import logging
18 import os
19 
20 import xmpp
21 from xmpp.protocol import Message
22 
23 from xmppbot import Bot, ConnectionError

Imports relatifs très déconseillés

Imports

Objectifs

  • Portabilité
  • Le moins d'ambiguïté possible
  • Lisibilité (encore, hé oui...)

Imports

Imports de classe intra-module

On peut faire :

1 from maclasse import MaClasse
2 from truc.chose.taclasse import TaClasse

En cas de "clash" :

1 import maclasse
2 import truc.chose.taclasse

Pour utiliser :

1 mon_objet = maclasse.MaClasse()
2 ton_autre_objet = truc.chose.taclasse.TaClasse()

Espaces dans les expressions

Règle : éviter les espaces superflus

Espaces dans les expressions

Parenthèses

ÇA C'EST NON

1 spam( ham[ 1 ], { eggs: 2 } )
2 dict ['key'] = list [index]

Espaces dans les expressions

Parenthèses

ÇA C'EST OUI

1 spam(ham[1], {eggs: 2})
2 dict['key'] = list[index]

Espaces dans les expressions

Virgules et points-virgules

ÇA C'EST NON

1 if x == 4 : print x , y ; x , y = y , x

Espaces dans les expressions

Virgules et points-virgules

un espace après

1 if x == 4: print x, y; x, y = y, x

Espaces dans les expressions

Chaque fois qu'un codeur perd du temps à faire ça...

1 x             = 1
2 y             = 2
3 long_variable = "quelle perte de temps!"

... $DIVINITE tue un petit chat

Voulez-vous me sauver la vie ?

Espaces dans les expressions

Restons sérieux

1 x = 1
2 y = 2
3 long_variable = "quel gain de temps"

Espaces dans les expressions

Les opérateurs

ÇA C'EST NON

1 i=i+1
2 submitted +=1
3 x = x*2 - 1
4 hypot2 = x*x + y*y
5 c = (a+b) * (a-b)

Espaces dans les expressions

Les opérateurs

ÇA C'EST OUI

1 i = i + 1
2 submitted += 1
3 x = x * 2 - 1
4 hypot2 = x * x + y * y
5 c = (a + b) * (a - b)

Espaces dans les expressions

Définitions et appels de fonction

ÇA C'EST NON

1 def complex(real, imag = 0.0):
2     return magic(r = real, i = imag)

Espaces dans les expressions

Définitions et appels de fonction

ÇA C'EST OUI

1 def complex(real, imag=0.0):
2     return magic(r=real, i=imag)

Une expression par ligne

Une expression par ligne

Pas encouragé

1 if foo == 'blah': do_blah_thing()
2 do_one(); do_two(); do_three()

Une expression par ligne

Plutôt mieux

1 if foo == 'blah':
2     do_blah_thing()
3 do_one()
4 do_two()
5 do_three()

Commentaires

Commentaires

  • des phrases, complètes
  • cohérentes avec le code (ne pas embrouiller les gens)
  • en anglais

Commentaires

En anglais ?

Python coders from non-English speaking countries: please write your comments in English, unless you are 120% sure that the code will never be read by people who don't speak your language.

traduction possible

Pour les codeurs Python de pays non-anglophones : merci d'écrire vos commentaires en anglais, à moins d'être sûr à 120% que le code ne sera jamais lu par quelqu'un qui ne parle pas votre langue.

-- Guido Van Rossum

Commentaires

  • Même indentation que le code qui les concerne
  • un "#" suivi d'un espace (sauf indentation dans le commentaire)
  • paragraphes séparés par un espace

Commentaires

Commentaires sur la même ligne

  • séparé par deux espaces après le code
  • éviter d'enfoncer les portes ouvertes

Commentaires

1 x = x + 1  # incrémente x
2 # mouais...
3 x = x + 1  # rajoute une marge
4 # mieux

Docstrings

O-bli-ga-toi-res

Où ça ?

Par-tout

Partout

Docstrings

Obligatoires

  • tous les modules publics
  • toutes les fonctions
  • toutes les classes
  • toutes les méthodes de ces classes

Docstrings

Optionnelles

  • méthodes non-publiques
  • compenser par un commentaire après le def

Docstrings

Référence : PEP257

 1 def get_foobang(plotz=None):
 2     """Return a foobang.
 3 
 4     Optional plotz says to frobnicate the bizbaz first.
 5 
 6     """
 7     bizbaz = Bizbaz()
 8     if plotz:
 9         bizbaz.frobnicate()
10     return Foobang(bizbaz)

En anglais itou

Version Bookkeeping

1 __version__ = "$Revision: 84354 $"
2 # $Source$

utile pour Subversion, CVS, RCS...

Conventions de nommage

Conventions de nommage

Plusieurs styles existants

  • b (une seule minuscule)
  • B (une seule majuscule)
  • minuscule
  • minuscules_avec_des_underscores
  • MAJUSCULE
  • MAJUSCULES_AVEC_DES_UNDERSCORES
  • MotsEnMajuscule (appelé souvent CamelCase)
  • motAvecCapitalisationMelangee (minuscule au premier mot)
  • Mots_En_Majuscule_Avec_Des_Underscores (berk !)

Conventions de nommage

Modules

  • nom court,
  • tout en minuscules
  • underscores si nécessaire

Paquetages

  • nom court,
  • tout en minuscules
  • underscore très déconseillé

noms de fichiers, répertoires, respect de la casse

Conventions de nommage

  • 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 de nommage

Public / privé

  • __my_private_variable ==> "privé"
  • _not_so_private ==> "protégé"

Évidemment, en Python...

  • rien n'est réellement privé
  • ce ne sont "que" des conventions

Engueuliche, eugueille noeud

Recommendations de codage

Recommendations de codage

Ne pas désavantager les implémentations de Python

  • PyPy
  • Jython
  • IronPython
  • Pyrex
  • Psyco

Recommendations de codage

Comparaisons avec None

1 x = None
2 if x:
3     print "on ne passe pas ici"
4 else:
5     print "on passera"

Recommendations de codage

Comparaisons avec None

1 x = ""
2 if x:
3     print "on ne passe pas ici"
4 else:
5     print "on passera"

Recommendations de codage

Comparaisons avec None

1 x = None
2 if x is None:
3     print "on passera ici"
4 else:
5     print "mais jamais ici"

Recommendations de codage

Cas spécial : les listes, tuples, chaînes

Une liste vide est False. Plus performant que len()

1 my_list = []
2 
3 if len(my_list) == 0:
4     print "je suis lent"
5 
6 if not my_list:
7     print "je suis rapide"

Recommendations de codage

Cas spécial : les booléens

1 if greetings:
2     print "good"
3 
4 if greetings == True:
5     print "not good"
6 
7 if greetings is True:
8     print "argh! even worse!"

Recommendations de codage

Exceptions

1 class MessageError(Exception):
2     pass
3 
4 raise MessageError, "Ouch! Here is my message!"

deux fautes - chaîne et docstring

Recommendations de codage

Exceptions

1 class MessageError(Exception):
2     """Base class for errors in the email package."""
3     pass
4 
5 raise MessageError("Ouch! Here is my message!")

Recommendations de codage

Exceptions

le "catch" doit être si possible spécifique

1 try:
2     import platform_specific_module
3 except ImportError:
4     platform_specific_module = None

Chaînes

méthodes de chaîne plutôt que le module string

Recommendations de codage

Chaînes

endswith ou startswith plutôt que le découpage des chaînes

1 if foo.startswith('bar'):
2     print "good"
3 
4 if foo[:3] == 'bar':
5     print "not good"

Game Over

?

Crédits

Présentation réalisée avec l'aide de Landslide, Scribes, Chromium, et Ubuntu.

Cette présentation est publiée sous contrat Creative Commons CC-BY-SA.

Images