G. Lghd
web developper
Emmanuelle R. et Gaëtan L.
21/01/2020
"La perfection est atteinte, non pas lorsqu'il n'y a plus rien à ajouter, mais lorsqu'il n'y a plus rien à retirer.“
Saint Exupery
l'idée de "sport collectif", de discipline :
Pourquoi ce sujet ?
D'un côté, il est important d'apprendre à respecter la règle du jeu càd des normes de développement : dans les méthodes, au fond, dans la forme.
D'un autre côté, le Python, par son mode communautaire, entretient un rapport spécifique à la qualité : le pythonique.
La simplicité est principe à la base de nombreuses règles de qualité, et Python notamment en Python.
Mies van der Rohe : directeur du Bauhaus (en informatique aussi on parle d'architecture…)
La qualité est là pour établir une règle du jeu :
Les finalités de la qualité d'un programme :
Ces finalités mettent en relation des lignes de code avec un contexte : un client, un utilisateur, d'autres programmeurs.
Le programmeur semble seul face à son code - et il en tire parfois une certaine jouissance. En fait, ce qu'il produit est un objet destiné à entrer dans un réseau de relations, et il doit en tenir compte ! dans une perspective temporelle : la dette technique doit être minimisée
Côté code, la qualité est un impératif qui pèse dans le succès - et le coût potentiel - d'une application.
« Pythonique » ?
Code Python bien conçu, un code idiomatique (en accord avec les règles d’usage du langage, et donc compréhensible par tout développeur).
PEP20 : le Zen de Python
20 règles Ecrite par Tim Peters. Celle-ci énonce les règles suivant un poème. On peut la retrouver via l’instruction import this dans un interpréteur Python.
class User:
def __init__(self, name):
self.name = name
class SecureUser(User):
def __init__(self, name, password):
super().__init__(name)
self.password = password
L’explicite est préférable à l’implicite.
Lire un code Python sans se demander sans cesse ce que fait telle ou telle ligne. Utiliser des noms et des constructions explicites.
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.
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 si de nombreux niveaux d’imbrications se succèdent.
Préférer donc d'éviter les imbrications inutile (code plat).
==> 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)
Keep it simple, stupid (KISS)
Il est inutile de créer de nouvelles classes trop vite.
Par exemple, pour un objet qui ne contiendrait que des données, associées à aucune méthode, un dictionnaire suffit:
user = {'username': 'Giles', 'realname': 'Giles Dupont', 'password': '12345'}
= Regrouper dans des fonctions, une action en une seule.
Chaque fonctions doit avoir une action a la fois, et c’est l'enchaînement des fonctions qui produit la fonctionnalité finale.
Tu n’en auras pas besoin
Les mécanismes du langage:
a = 5
b = 2
a, b = b, a
print(a, b)
2 5
Technique qui permet l’assignation de plusieurs variables en une seule instruction.
Ce qui se passe en interne lors de la 3ème ligne est la création d’un tuple (b, a), qui est ensuite déconstruit et son contenu stocké dans les variables a et b.
Toute valeur en Python peut s’évaluer sous forme d’un booléen, sans conversion.
if ma_liste:
print("non vide")
La bibliothèque standard
Les fonctions Built-in:
Voir la liste exhaustive sur : Built-in Functions — Python 3.8.1 documentation
ex: min(), max(), sum(), sorted(), etc.
print('{} + {} = {}'.format(2, 3, 2 + 3))
.format():
.zip()
x = [1, 2, 3]
y = [4, 5, 6]
zipped = zip(x, y)
Un exemple:
with open(pythonique, 'r') as f:
for i in enumerate(f):
longueur = abc.split(',')
for i in range (1, nb):
...
# et non: for i in range (nb-1):
for i in mylist:
# et non : for i in len(mylist) /
# + increment
Différents paradigmes de programmation ont un impact
sur la qualité du code :
POO : tout le monde est d'accord sur les méthodes
et sur les propriétés des objets : en Python, tout est objet
On l'a vu en introduction, parallèle possible avec le design, qui implique aussi un collectif.
=> en programmation : les design patterns
Programmation fonctionnelle : tout le monde est d'accord sur les variables, standardisation de la forme des fonctions
Dans un cadre professionnel, des méthodes renforcent aussi la qualité des spécifications, des livrables : l'agilité par exemple.
Pas d'assez d'expérience en ce domaine pour l'évoquer plus, et cela nous écarterait du sujet de l'approfondir alors que nous l'aborderons prochainement. Rappelons justes deux des maximes "professionnelles" de la PEP 20 : "Maintenant est préférable à jamais.", "Bien que jamais soit souvent préférable à tout de suite."
Eviter l'urgence ne signifie pas procrastiner : maintenant > jamais > tout de suite
La PEP8:
Style Guide for Python Code: une des plus anciennes
Le site pep8online permet de vérifier si son code respecte ce guide.
L'indentation, tabulations ou espaces
if True:
print("True")
print("False")
Longueur maximum d'une ligne
Un_long_calcul = variable + \
taux * 100
Parenthèses culture générale:
Traditionnellement les terminaux des années 80 etaient limités à 80 colonnes et 24 lignes. Standard VT100:
Traditionnellement les terminaux des années 80 etaient limités à 80 colonnes et 24 lignes. Standard VT100:
20 tabulations == 80 espaces == 1 ligne
Parenthèse culture générale :
Directives d'importation
import os
import math
# et non
import os, math
from random import randomint
# et surtout pas:
from random import *
sauf :
Dans l'ordre :
les directives d'importation faisant référence à la bibliothèque standard ;
les directives d'importation faisant référence à des bibliothèques tierces ;
les directives d'importation faisant référence à des modules de votre projet.
Le signe espace dans les expressions et instructions
pas d'espace :
# Oui
spam(salade[1], {oeufs: 2})
# Non
spam( salade[ 1 ], { oeuf: 2 } )
# Oui
spam(1)
# Non
spam (1)
# Oui
if x == 4: print x, y; x, y = y, x
# Non
if x == 4 : print x , y ; x , y = y , x
def fonction(parametre=5):
i = i + 1
# NON
def fonction (parametre = 5):
i=i+1
La PEP 257 : de belles documentations
https://www.python.org/dev/peps/pep-0257/
Cette chaîne de caractères devient l'attribut spécial__doc__de l'objet:
fonction.__doc__
'Documentation de la fonction.'
def fonction():
"""Documentation brève sur une ligne.
Documentation plus longue...
"""
En bref:
Le BDFL ( Benevolent Dictator For Life) conseille de sauter une ligne avant de fermer les docstrings, si sur plusieurs lignes.
Conventions de nommage
Astuce: Depuis python 3.8.1, Il existe un moyen de faire des Constantes avec python:
from typing import Final
MA_CONSTANTE: Final = 1
https://docs.python.org/3/library/typing.html
By G. Lghd
sujet de veille pour la formation CDA Python à Simplon