IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)

Python, de zéro


précédentsommairesuivant

XXVI. Divers

XXVI-1. Python Enhancement Proposals (PEP)

Les PEP (Python Enhancement Proposals) sont des propositions d’améliorations du langage et de sa bibliothèque standard. On y trouve aussi des conseils d’écriture pour obtenir un code facilement lisible. On trouvera par exemple les conseils suivants (liste non exhaustive) :

  • mettre des espaces avant et après les opérateurs de comparaison (if a == b et non if a==b) ;
  • mettre des espaces dans les affectations (= None et non a=None) ;
  • mettre des espaces avant et après le deux‑points séparant les clefs des valeurs dans un dictionnaire (= {1 : "toto"} et non = {1:"toto"}) ;
  • mettre un espace après la virgule (tp = (123) et non tp = (1,2,3)) ;
  • ne pas écrire de lignes de plus de 80 caractères. On peut parfaitement découper des instructions mêmes complexes sur plusieurs lignes (quitte à protéger la fin de ligne, symbolisant l’exécution de l’action, par un backslash inhibiteur…) ;
Incorrect
Sélectionnez
1.
2.
3.
4.
var=("Pim", "Pam", "Poum")
if var[0] == "Pim" and var[1] == "Pam" and var[2] == "Poum" :
…
string="La raison du plus fort est toujours la meilleure"
Correct
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
var=(
    "Pim",
    "Pam",
    "Poum",
)
if var[0] == "Pim"\
and var[1] == "Pam"\
and var[2] == "Poum" :
…
string="La raison du plus fort"\
+ " est toujours la meilleure."
  • ne pas mettre de virgule après le dernier élément d’un itérable (tp = (123) et non tp = (123,)), excepté pour les itérables écrits sur plusieurs lignes ou les tuples n’ayant qu’un seul élément, car là, c’est la virgule qui fait le tuple (tp = (1,)) ;
  • même pour les fonctions à une instruction, préférer les définitions de fonctions explicites aux lambdas ;
Incorrect
Sélectionnez
1.
carre=lambda x : x*x
Correct
Sélectionnez
1.
def carre(x) : return x*x
  • limiter les gestions d’exceptions aux seules instructions pouvant amener l’exception plutôt que regrouper plusieurs instructions sans pouvoir distinguer ensuite laquelle a provoqué l’exception ;
Incorrect
Sélectionnez
1.
2.
3.
4.
try:
    return fct(collection[key])
except KeyError:
    return key_not_found(key)
Correct
Sélectionnez
1.
2.
3.
4.
5.
6.
try:
    value=collection[key]
except KeyError:
    return key_not_found(key)
else:
    return fct(value)
  • expliciter le return None implicite.
Incorrect
Sélectionnez
1.
2.
def racine(x):
    if x >= 0: return x**0.5
Incorrect
Sélectionnez
1.
2.
3.
def racine(x):
    if x < 0: return
    return x**0.5
Correct
Sélectionnez
1.
2.
3.
def racine(x):
    if x >= 0: return x**0.5
    return None
Correct
Sélectionnez
1.
2.
3.
def racine(x):
    if x < 0: return None
    return x**0.5

XXVI-2. Zen de Python

Le Zen de Python est un ensemble de 19 principes qui influencent la conception du langage de programmation Python et sont utiles pour comprendre et utiliser le langage.

Écrit et publié sur la liste de discussion de Python en juin 1999 par Tim Peters, le Zen de Python a été ensuite publié comme le PEP 203, il est aussi présent (en anglais) sur le site web officiel de Python. Il est également inclus comme « Easter egg » dans la distribution de l'interpréteur Python et apparait quand on tape la commande import this dans la console Python.

Beauté vaut mieux que laideur.
Explicite vaut mieux qu'implicite.
Simple vaut mieux que complexe.
Complexe vaut mieux que compliqué.
Linéaire vaut mieux qu’imbriqué.
Aéré vaut mieux que dense.
La lisibilité compte.
Les cas particuliers ne le sont pas assez pour enfreindre les règles.
Mais, à la pureté, privilégie l'aspect pratique.
Les erreurs ne doivent jamais être passées sous silence.
Sauf si explicitement réduites au silence.
Face à l'ambiguïté, refusez la tentation de deviner.
Il devrait y avoir une, et de préférence une seule, manière évidente de le faire.
Bien que cela ne soit pas évident immédiatement, à moins que vous ne soyez néerlandais(2).
Mieux vaut maintenant que jamais.
Mais jamais est souvent mieux qu'immédiatement.
Si la mise en œuvre est difficile à expliquer, c'est une mauvaise idée.
Si la mise en œuvre est facile à expliquer, cela peut être une bonne idée.
Les espaces de noms sont une excellente idée, il faut les utiliser.

XXVI-3. Les docstrings

Les docstrings sont un mécanisme permettant d’automatiser les tests unitaires et la documentation du code qui sont, comme tout développeur le sait, les tâches les plus pénibles de son métier.

Là encore, la philosophie Python entre en jeu, car moins il y a de freins, plus il y a de chances qu’on le fasse.

Le principe de la docstring est d’encadrer un texte par trois guillemets doubles (") accolés.

Exemple :

 
Sélectionnez
1.
2.
3.
4.
def ajouter(a, b):
    """ Ajoute deux nombres l'un à l'autre et retourne le résultat. """

    return a + b

En dehors de l’avantage principal que de pouvoir comprendre facilement ce que fait telle ou telle fonction simplement en ouvrant le script, la docstring est aussi lue par Python pour pouvoir générer l’aide associée à la fonction lors de l’appel à help().

 
Sélectionnez
1.
2.
3.
4.
>>> help(ajouter)
Help on function ajouter in module __main__:
ajouter(a, b)
Additionne deux nombres et retourne le résultat.

La docstring peut s’étendre sur plusieurs lignes, être intégrée aux classes et aussi aux méthodes…

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
class StarTrek:
    """
    Cette classe vous donne accès à l’univers StarTrek
    Un univers sans limites.
    """

    def where_no_one_has_gone_before(self):
        """
        Vous envoie là où personne n’est allé avant vous
        """
        pass

Une demande d’aide sur l’objet se traduira par l’affichage de sa docstring…

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
>>> help(StarTrek)
Help on class StarTrek in module __main__:

class StarTrek(__builtin__.object)
 |  Cette classe vous donne accès à l’univers StarTrek
 |  Un univers sans limites.
 | 
 |  Methods defined here:
 | 
 |  where_no_one_has_gone_before(self)
 |    Vous envoie là où personne n’est allé avant vous

… ainsi qu’une demande d'aide sur l’une de ses méthodes.

 
Sélectionnez
1.
2.
3.
4.
5.
>>> help(StarTrek.where_no_one_has_gone_before)
Help on method where_no_one_has_gone_before in module __main__:

where_no_one_has_gone_before(self) unbound b.StarTrek method
    Vous envoie là où personne n’est allé avant vous

XXVI-4. La bonne façon de faire ses tests

Il y a plusieurs façons de tester les éléments dans Python, façons qui se traduisent par autant de symboles voire de mots clefs distincts (=, is, in, etc.). Toutes fonctionneront dans la quasi-totalité des situations. Mais toutes ne seront pas aussi efficaces selon la nature de l’élément testé.

Pour tester une valeur concrète, on utilisera les opérateurs usuels de relation d’ordre (« égal à », « différent de », etc.).

 
Sélectionnez
1.
2.
3.
4.
>>> var=5
>>> if var <= 5: print("ok")
…
ok

Pour tester une valeur booléenne, on utilisera directement la valeur dans la condition. Éventuellement précédée de not si nécessaire.

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
>>> var1=True
>>> if var1: print("ok")
…
ok
>>> var2=False
>>> if not var2: print("ok")
…
ok

Pour tester la valeur spéciale None, on utilisera l’opérateur is indiquant l’état. Car d'une part None n’est pas une valeur, c’est un état et d'autre part l'opérateur is est le seul opérateur qui ne puisse pas être surchargé.

On peut bien entendu ne pas suivre ces préconisations et utiliser par exemple is pour une égalité (ex if var is 5). Mais d'une part Python devra pour cela faire des transformations implicites qui ralentiront le processus et d'autre part cela peut parfois ne pas fonctionner.

Exemple de comparaison d'une instance de classe avec None :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
>>> class toto:
…    def __eq__(self, x): return Truedef __ne__(self, x): return False>>> toto() == None
True
>>> toto() != None
False

Comme les opérateurs de comparaison ont été réécrits, le résultat donne n'importe quoi. Alors que si l’on utilise la bonne façon de faire…

 
Sélectionnez
1.
2.
3.
4.
>>> toto() is None
False
>>> toto() is not None
True

… le résultat est correct.

Exemple d'évaluation booléenne d'une chaîne non vide (donc considérée comme True) :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
>>> var="Hello"
>>> if var is True: print("ok")
…
>>> if var == True: print("ok")
…
>>>

Même si une chaîne non vide est « considérée » comme vraie, elle n'est pas strictement égale à True. Et donc ces tests ne donnent pas le résultat attendu. Alors qu'en employant la méthode adéquate d'une évaluation booléenne…

 
Sélectionnez
1.
2.
3.
>>> if var: print("ok")
…
ok

… le résultat est là aussi correct.

XXVI-5. Différences entre Python 2 et Python 3

Voici une liste non exhaustive des différences entre Python 2 et Python 3

 

Python 2

Python 3

Type int

Valeur numérique entière pouvant aller approximativement de -2^62 à 2^62

Valeur numérique entière virtuellement infinie

Type long

Valeur numérique entière virtuellement infinie

N’existe plus

Opérateur slash (/)

Division selon le type le plus précis des opérandes impliqués. Une division impliquant un flottant sera exacte, mais une division de deux entiers sera entière

Division exacte

Instruction print

Peut s’utiliser comme une instruction ou comme une fonction

Devenue fonction, obligation de mettre des parenthèses

Instruction yield from iterable

N’existe pas

Crée un générateur sur chaque élément de l’itérable

Une chaîne xxx ou r"xxx"

Est encodée en ASCII et est du type str

Est encodée en Unicode et est du type str

Une chaîne b"xxx"

Est encodée en ASCII et est du type str

Est encodée en ASCII et est du type bytes

Une chaîne f"xxx"

N’existe pas

Permet d’insérer des variables ou des expressions directement dans la chaîne

Une chaîne u"xxx"

Est encodée en Unicode et est du type unicode

Est encodée en Unicode et est du type str

Fonction bytes()

N’existe pas

Renvoie une chaîne encodée en ASCII

Fonction cmp()

Compare ses arguments et retourne une valeur numérique indiquant si l’argument de gauche est plus petit, égal ou plus grand que l’argument de droite

N’existe plus

Fonction input()

Permet de faire saisir une valeur qui sera typée selon sa syntaxe de saisie

Permet de faire saisir une valeur qui sera typée str

Fonction map()

Renvoie une liste

Renvoie un objet map

Fonction range()

Renvoie une liste

Renvoie un objet range

Fonction raw_input()

Permet de faire saisir une valeur qui sera typée str

N’existe plus

Fonction reduce()

Est une fonction native

A été déportée dans le module functools

Fonction str()

Renvoie une chaîne encodée en ASCII

Renvoie une chaîne encodée en Unicode

Fonction unicode()

Renvoie une chaîne encodée en Unicode

N'existe plus

Fonction xrange()

Renvoie un générateur

N’existe plus

Méthodes dict.keys(), dict.values() et dict.items()

Renvoient des listes

Renvoient des objets dict_keys, dict_values et dict_items (ce sont des objets dynamiques qui se synchronisent automatiquement en cas d'évolution du dictionnaire)

Méthodes dict.iterkeys(), dict.itervalues() et dict.iteritems()

Renvoient des objets dictionary_keyiterator, dictionary_valueiterator et dictionary_itemiterator (ce sont des générateurs qui sont donc n’utilisables qu’une seule fois et qui renvoient une exception RuntimeError si le dictionnaire est modifié entre leur création et leur utilisation)

N’existent plus

Méthodes dict.viewkeys(), dict.viewvalues() et dict.viewitems()

Renvoient des objets dict_keys, dict_values et dict_items (ce sont des objets dynamiques qui se synchronisent automatiquement en cas d'évolution du dictionnaire)

N’existent plus

Méthode generator.next()

Renvoie l’élément suivant du générateur

N’existe plus

Méthode list.clear()

N’existe pas

Vide la liste

Méthode object.__bool__()

N’existe pas

Est utilisée quand on demande bool(object)

Méthode object.__bytes__()

N’existe pas

Est utilisée quand on demande bytes(object)

Méthode object.__cmp__()

Permet de définir une méthode de comparaison générale

N’existe plus

Méthode object.__div__() et object.__rdiv__()

Permettent de redéfinir la division dans un objet

N’existent plus

Méthode object.__nonzero__()

Est utilisée quand on demande bool(object)

N’existe plus

Méthode object.__truediv__() et object.__rtruediv__(

N’existent pas

Permettent de redéfinir la division exacte dans un objet

Méthode object.__unicode__()

Est utilisée quand on demande unicode(object)

N’existe plus

Paramètre *args

Doit être placé en dernière position des paramètres ou en avant-dernière si le paramètre **kwargs (qui, lui, sera impérativement placé en dernier) est présent

Peut être placé à n’importe quelle position des paramètres à l'exception de la dernière si le paramètre **kwargs (qui, lui, sera impérativement placé en dernier) est présent

Argument cmp de la fonction sort()

Permet de spécifier une fonction qui aura pour charge de comparer deux éléments à trier

N'existe plus. Son fonctionnement est reproduit par l'objet cmp_to_key() du module functools, objet qui convertit une fonction en clef, et qu'on passera à l'argument key

exec et print

Sont des mots clefs

Sont des mots sans signification particulière

nonlocal

Est un mot sans signification particulière

Est un mot clef

None, True et False

Sont des variables globales

Sont des mots clefs

L'héritage de l'objet primitif object

Doit être explicitement demandé

Est intégré en natif dans les objets de l'utilisateur

Fonction super()

Doit contenir impérativement deux arguments : le type de l’objet dans lequel elle est appelée et l’instance de l’objet qui l’appelle (self)

Les arguments type et instance sont facultatifs


précédentsommairesuivant
Certaines traductions remplacent « néerlandais » par « allemand ». Quant à la raison de cette remarque… ?

Copyright © 2022 Svear (svear@free.fr) Permission est accordée de copier, distribuer ou modifier ce document selon les termes de la « Licence de Documentation Libre GNU » (GNU Free Documentation License), version 1.1 ou toute version ultérieure publiée par la Free Software Foundation.