Annexe C. Trucs et astuces
Chapitre 1. Installation de Python
Chapitre 2. Votre premier programme Python
- 2.1. Plonger
|
Dans l'IDE ActivePython
sous Windows, vous pouvez exécuter le programme Python que vous êtes en train d'éditer par -> (Ctrl-R). La sortie est affichée dans la fenêtre
interactive.
|
|
Dans l'IDE Python
sous Mac OS, vous pouvez exécuter
un module avec -> (Cmd-R) mais il y a une option importante que vous devez
activer préalablement. Ouvrez le module dans l'IDE,
ouvrez le menu des options des modules en cliquant le triangle noir
dans le coin supérieur droit de la fenêtre et assurez-vous que
«» est coché. Ce réglage est sauvegardé avec le
module, vous n'avez donc à faire cette manipulation qu'une fois par
module.
|
|
Sur les systèmes compatibles UNIX (y compris
Mac OS X), vous pouvez exécuter un programme Python
depuis la ligne de commande : python
odbchelper.py |
- 2.2. Déclaration de fonctions
|
En Visual Basic, les fonctions (qui
retournent une valeur) débutent avec function et
les sous-routines (qui ne retourne aucune valeur) débutent avec
sub. Il n'y a pas de sous-routines en
Python. Tout est fonction, toute fonction
retourne un valeur (même si c'est None) et toute
fonction débute avec def.
|
|
En Java,
C++ et autres langage à
typage statique, vous devez spécifier les types de données de la
valeur de retour d'une fonction ainsi que de chaque paramètre. En
Python, vous ne spécifiez jamais de manière
explicite le type de quoi que ce soit. En se basant sur la valeur que
vous lui assignez, Python gère les types de
données en interne.
|
- 2.3. Documentation des fonctions
|
Les triples guillemets sont aussi un moyen simple de définir une
chaîne contenant à la fois des guillemets simples et doubles, comme
qq/.../ en Perl.
|
|
Beaucoup d'IDE Python utilisent les doc string pour fournir une documentation contextuelle, ainsi lorsque vous tapez le nom d'une fonction, sa doc string apparaît dans une bulle d'aide. Cela peut être incroyablement utile, mais cette utilité est liée à la qualité de votre doc string.
|
- 2.4. Tout est objet
|
import en Python est similaire à require en Perl. Une fois que vous importez un module
Python, vous accédez à ses fonctions avec module.function. Une fois que vous incluez un module Perl, vous accédez à ses fonctions avec module::function.
|
- 2.5. Indentation du code
|
Python utilise le retour chariot pour séparer les instructions, deux points et l'indentation pour séparer les blocs de code. C++ et Java utilisent des points-virgules pour séparer les instructions et des accolades pour séparer les blocs de code.
|
- 2.6. Test des modules
|
A l'instar de C, Python utilise == pour la comparaison et = pour l'assignement. Mais au contraire de C, Python ne permet pas les assignations dans le corps d'une instruction afin d'éviter qu'une valeur soit accidentellement assignée
alors que vous pensiez effectuer une simple comparaison.
|
|
Avec MacPython, il y a une étape
supplémentaire pour que l'astuce if
__name__ fonctionne. Ouvrez le menu des options des
modules en cliquant le triangle noir dans le coin supérieur droit de
la fenêtre et assurez-vous que est coché.
|
Chapitre 3. Types prédéfinis
- 3.1. Présentation des dictionnaires
|
En Python, un dictionnaire est comme
une table de hachage en Perl. En
Perl, les variables qui stockent des tables
de hachage débutent toujours par le caractère %. En
Python vous pouvez nommer votre variable
comme bon vous semble et Python se chargera
de la gestion du typage.
|
|
Un dictionnaire Python est similaire
à une instance de la classe Hashtable en
Java.
|
|
Un dictionnaire Python est similaire
à une instance de l'objet Scripting.Dictionnary
en Visual Basic.
|
- 3.1.2. Modification des dictionnaires
|
Les dictionnaires ne sont liés à aucun concept d'ordonnancement
des éléments. Il est incorrect de dire que les élément sont
«dans le désordre», il ne sont tout simplement pas
ordonnés. C'est une distinction importante qui vous ennuiera lorsque
vous souhaiterez accéder aux éléments d'un dictionnaire d'une façon
spécifique et reproductible (par exemple par ordre alphabétique des
clés). C'est possible, mais cette fonctionalite n'est pas integrée
au dictionnaire.
|
- 3.2. Présentation des listes
|
Une liste en Python est comme un
tableau Perl. En
Perl, les variables qui stockent des
tableaux débutent toujours par le caractère @, en
Python vous pouvez nommer votre variable
comme bon vous semble et Python se chargera
de la gestion du typage.
|
|
Une liste Python est bien plus qu'un
tableau en Java (même s'il peut être utilisé comme tel si vous
n'attendez vraiment rien de mieux de la vie). Une meilleure analogie
serait la classe ArrayList, qui peut contenir
n'importe quels objets et qui croît dynamiquement au fur et à mesure
que de nouveaux éléments y sont ajoutés.
|
- 3.2.3. Recherche dans une liste
|
Avant la version 2.2.1, Python
n'avait pas de type booléen. Pour compenser cela,
Python acceptait pratiquement n'importe
quoi dans un contexte requérant un booléen (comme une instruction
if), en fonction des règles suivantes :
- 0 est faux, tous les autres nombres sont vrai.
- Une chaîne vide ("") est faux, toutes les autres chaînes sont vrai.
- Une liste vide ([]) est faux, toutes les autres listes sont vrai.
- Un tuple vide (()) est faux, tous les autres tuples sont vrai.
- Un dictionnaire vide ({}) est faux, tous les autres dictionnaires sont vrai.
Ces règles sont toujours valides en Python 2.3.3 et au-delà, mais vous pouvez maintenant utiliser un véritable booléen, qui a pour valeur True ou False. Notez la majuscule, ces valeurs comme tout le reste en Python, sont sensibles à la casse.
|
- 3.3. Présentation des tuples
|
Les tuples peuvent être convertis en listes et vice-versa. La
fonction prédéfinie tuple prends une liste et
retourne un tuple contenant les mêmes éléments et la fonction
list prends un tuple et retourne une liste. En
fait, tuple gèle une liste et
list dégèle un tuple.
|
- 3.4. Définitions de variables
|
Lorsq'une commande est étalée sur plusieurs lignes avec le
marqueur de continuation de ligne
(«\»), les lignes suivantes peuvent
être indentées de n'importe qu'elle manière, les règles d'indentation
strictes habituellement utilisées en Python
ne s'appliquent pas. Si votre IDE
Python indente automatiquement les lignes
continuées, vous devriez accepter ses réglages par défauts sauf raison
impérative.
|
- 3.5. Formatage de chaînes
|
Le formatage de chaînes en Python
utilise la même syntaxe que la fonction
C
sprintf.
|
- 3.7. Jointure de listes et découpage de chaînes
|
La méthode join ne fonctionne qu'avec des
listes de chaînes; elle n'applique pas la conversion de types. La
jointure d'une liste comprenant au moins un
élément non-chaîne déclenchera une exception.
|
|
une_chaîne.split(delimiteur, 1) est une technique utile pour chercher une sous-chaîne dans une chaîne et utiliser tout ce qui précède cette sous-chaîne (le
premier élément de la liste retournée) et tout ce qui la suit (le second élément de la liste retournée).
|
Chapitre 4. Le pouvoir de l’introspection
- 4.2. Arguments optionnels et nommés
|
La seule chose que vous avez à faire pour appeler une fonction
est de spécifier une valeur (d’une manière ou d’une autre) pour chaque
argument obligatoire, la manière et l’ordre dans lequel vous le faites
ne dépendent que de vous.
|
- 4.3.3. Fonctions prédéfinies
|
Python est fourni avec d’excellent
manuels de référence que vous devriez parcourir de manière exhaustive
pour apprendre tous les modules que Python
offre. Mais alors que dans la plupart des langages vous auriez à vous
référer constamment aux manuels (ou aux pages man, ou pire,
à MSDN) pour vous rappeler l’usage de ces modules,
Python est en grande partie
auto-documenté.
|
- 4.7. Utiliser des fonctions lambda
|
Les fonctions lambda sont une question de
style. Les utiliser n’est jamais une nécessité, partout où vous pouvez
les utiliser, vous pouvez utiliser une fonction ordinaire. Je les
utilise là où je veux incorporer du code spécifique et non
réutilisable sans encombrer mon code de multiples fonctions d’une
seule ligne.
|
- 4.8. Assembler les pièces
|
En SQL, vous devez utiliser IS
NULLmethod au lieu de = NULL pour la
comparaison d’une valeur nulle. En Python,
vous pouvez utiliser aussi bien == None que
is None, mais is None est plus
rapide.
|
Chapitre 5. Les objets et l'orienté objet
- 5.2. Importation de modules avec from module import
|
from module import * en Python est comme use module in Perl. import module en Python est comme require module en Perl.
|
|
from module import * en Python est comme import module.* en Java. import module en Python est comme import module en Java.
|
|
Utilisez from module import * avec modération, il rend plus difficile de déterminer l'origine d'une fonction ou d'un attribut, ce qui rend le débogage
et la refactorisation plus difficiles.
|
- 5.3. Définition de classes
|
L'instruction pass de
Python est comme une paire d'accolades vide
({}) en Java ou
C.
|
|
En Python, l'ancêtre d'une classe est
simplement indiqué entre parenthèses immédiatement après le nom de la
classe. Il n'y a pas de mot clé spécifique comme
extends en Java.
|
- 5.3.1. Initialisation et écriture de classes
|
Par convention, le premier argument d'une méthode de classe (la
référence à l'instance en cours) est appelé self.
Cet argument remplit le rôle du mot réservé this en
C++ ou Java, mais self n'est
pas un mot réservé de Python, seulement une
convention de nommage. Cependant, veuillez ne pas l'appeler autre chose
que self, c'est une très forte convention.
|
- 5.3.2. Quand utiliser self et __init__
|
Les méthodes __init__ sont optionnelles,
mais quand vous en définissez une, vous devez vous rappeler d'appeler
explicitement la méthode __init__ de l'ancêtre de
la classe. C'est une règle plus générale : quand un descendant veut
étendre le comportement d'un ancêtre, la méthode du descendant doit
appeler la méthode de l'ancêtre explicitement au moment approprié,
avec les arguments appropriés.
|
- 5.4. Instantiation de classes
|
En Python, vous appelez simplement
une classe comme si c'était une fonction pour créer une nouvelle
instance de la classe. Il n'y a pas d'opérateur new
explicite comme pour C++
ou Java.
|
- 5.5. UserDict : une classe enveloppe
|
Dans l'IDE ActivePython sous Windows, vous pouvez ouvrir rapidement n'importe quel module dans votre chemin de bibliothèques avec
-> (Ctrl-L).
|
|
Java et
Powerbuilder supportent la surcharge de
fonction par liste d'arguments : une classe peut avoir différentes
méthodes avec le même nom mais avec un nombre différent d'arguments
ou des arguments de type différent. D'autres langages (notamment
PL/SQL) supportent même la surcharge de fonction
par nom d'argument : une classe peut avoir différentes méthodes avec
le même nom et le même nombre d'arguments du même type mais avec des
noms d'arguments différents. Python ne
supporte ni l'une ni l'autre, il n'a tout simplement aucune forme de
surcharge de fonction. Les méthodes sont définies uniquement par leur
nom et il ne peut y avoir qu'une méthode par classe avec le même nom.
Donc si une classe descendante a une méthode
__init__, elle redéfinit
toujours la méthode __init__
de la classe ancêtre, même si la descendante la définit
avec une liste d'arguments différente. Et la même règle s'applique
pour toutes les autres méthodes.
|
|
Guido, l'auteur originel de Python,
explique la redéfinition de méthode de cette manière : «Les classes
dérivées peuvent redéfinir les méthodes de leur classes de base.
Puisque les méthodes n'ont pas de privilèges spéciaux lorsqu'elles
appellent d'autres méthodes du même objet, une méthode d'une classe de
base qui appelle une autre méthode définie dans cette même classe de
base peut en fait se retrouver à appeler une méthode d'une classe
dérivée qui la redéfini (pour les programmeurs C++ cela veut dire
qu'en Python toutes les méthodes sont
virtuelles).» Si cela n'a pas de sens pour vous (personellement, je
m'y perd complètement) vous pouvez ignorer la question. Je me suis
juste dit que je ferais circuler l'information.
|
|
Assignez toujours une valeur initiale à toutes les données
attributs d'une instance dans la méthode
__init__. Cela vous épargera des heures de
débogage plus tard, à la poursuite d'exceptions
AttributeError pour cause de référence à des
attributs non-initialisés (et donc non-existants).
|
|
Dans les versions de Python
antérieures à la 2.2, vous ne pouviez pas directement dériver les
types de données prédéfinis comme les chaînes, les listes et les
dictionnaires. Pour compenser cela, Python
est fourni avec des classes enveloppes qui reproduisent le
comportement de ces types de données prédéfinis :
UserString, UserList et
UserDict. En utilisant un mélange de méthodes
ordinaires et spéciales, la classe UserDict
fait une excellente imitation d'un dictionnaire, mais c'est juste une
classe comme les autres, vous pouvez donc la dériver pour créer des
classes personalisées semblables à un dictionnaire comme
FileInfo. En Python
2.2 et suivant, vous pourriez récrire l'exemple de ce chapitre de
manière à ce que FileInfo hérite directement de
dict au lieu de
UserDict. Cependant, vous devriez quand même
lire l'explication du fonctionnement de
UserDict au cas où vous auriez besoin
d'implémenter ce genre d'objet enveloppe ou au cas où vous auriez à
travailler avec une version de Python antérieure à la 2.2.
|
- 5.6.1. Lire et écrire des éléments
|
Lorsque vous accédez à des données attributs dans une classe,
vous devez qualifier le nom de l'attribut :
self.attribute. Lorsque
vous appelez d'autres méthodes dans une classe, vous devez qualifier
le nom de la méthode :
self.method.
|
- 5.7. Méthodes spéciales avancées
|
En Java, vous déterminez si deux
variables de chaînes référencent la même zone mémoire à l'aide de
str1 == str2. On appelle cela
identité des objets et la syntaxe
Python en est str1 is
str2. Pour comparer des valeurs de chaînes en
Java, vous utiliseriez
str1.equals(str2), en
Python, vous utiliseriez str1 ==
str2. Les programmeurs Java qui
ont appris que le monde était rendu meilleur par le fait que
== en Java fasse une
comparaison par identité plutôt que par valeur peuvent avoir des
difficultés à s'adapter au fait que Python
est dépourvu d'un tel piège.
|
|
Alors que les autres langages orientés objet ne vous laissent
définir que le modèle physique d'un objet («cet objet a une
méthode GetLength»), les méthodes
spéciales de Python comme
__len__ vous permettent de définir le modèle
logique d'un objet («cet objet a une longueur»).
|
- 5.8. Attributs de classe
|
En Java, les variables statiques
(appelées attributs de classe en Python)
aussi bien que les variables d'instance (appelées données attributs en
Python) sont définies immédiatement après
la définition de la classe (avec le mot-clé static
pour les premières). En Python, seuls les
attributs de classe peuvent être définis à cet endroit, les données
attributs sont définies dans la méthode
__init__.
|
|
Il n'y a pas de constantes en
Python. Tout est modifiable en faisant
un effort. C'est en accord avec un des principes essentiels de
Python : un mauvais comportement doit
être découragé mais pas interdit. Si vous voulez vraiment changer la
valeur de None, vous pouvez le faire, mais ne
venez pas vous plaindre que votre code est impossible à
déboguer.
|
- 5.9. Fonctions privées
|
En Python, toutes les méthodes
spéciales (comme __setitem__)
et les attributs prédéfinis (comme __doc__) suivent
une convention standard : il commencent et se terminent par deux
caractères de soulignement. Ne nommez pas vos propres méthodes et
attributs de cette manière, cela n'apporterait que de la confusion
pour vous et les autres.
|
Chapitre 6. Traitement des exceptions et utilisation de fichiers
- 6.1. Traitement des exceptions
|
Python utilise try...except pour gérer les exceptions et
raise pour les générer. Java et C++ utilisent
try...catch pour gérer les exceptions et
throw pour les générer.
|
- 6.5. Travailler avec des répertoires
|
A chaque fois que c’est possible, vous devriez utiliser les
fonction de os et os.path pour les manipulations de
fichier, de répertoire et de chemin. Ces modules enveloppent des
modules spécifiques aux plateformes, les fonctions comme
os.path.split marchent donc sous
UNIX, Windows, Mac OS et toute autre plateforme supportée par
Python.
|
Chapitre 7. Expressions régulières
- 7.4. Utilisation de la syntaxe {n,m}
|
Il n’y a aucun moyen de déterminer par un programme que deux expressions régulières sont équivalentes. Le mieux que vous puissiez
faire est d’écrire de nombreux cas de test pour vérifier que leur comportements sont identiques pour les entrées pertinentes.
Nous discuterons plus en détail l’écriture de cas de tests plus loin dans le livre.
|
Chapitre 8. Traitement du HTML
- 8.2. Présentation de sgmllib.py
|
Python 2.0 avait un bogue qui
empêchait SGMLParser de reconnaître les
déclarations (handle_decl n’était jamais appelé),
ce qui veut dire que les DOCTYPEs étaient ignorés
silencieusement. Ce bogue est corrigé dans
Python 2.1.
|
|
Dans l’IDE ActivePython
sous Windows, vous pouvez spécifier des arguments de ligne de commande
dans la boîte de dialogue «Run script». Séparez les
différents arguments par des espaces.
|
- 8.4. Présentation de BaseHTMLProcessor.py
|
La spécification HTML exige que tous les
éléments non-HTML (comme le
JavaScript côté client) soient compris dans
des commentaires HTML, mais toutes les pages web ne
le font pas (et les navigateurs web récents ne l’exigent pas).
BaseHTMLProcessor, lui, l’exige, si le script
n’est correctement encadré dans un commentaire, il sera analysé comme
s’il était du code HTML. Par exemple, si le script
contient des signes inférieurs à ou égal,
SGMLParser peut considérer à tort qu’il a
trouvé des balises et des attributs. SGMLParser
convertit toujours les noms de balises et d’attributs en minuscules,
ce qui peut empêcher la bonne exécution du script et
BaseHTMLProcessor entoure toujours les valeurs
d’attributs entre guillemets (même si le document
HTML n’en utilisait pas ou utilisait des guillemets
simples), ce qui empêchera certainement l’exécution du script.
Protégez toujours vos script côté client par des commentaires
HTML.
|
- 8.5. locals et globals
|
Python 2.2 a introduit une
modification légère mais importante qui affecte l’ordre de recherche
dans les espaces de noms : les portées imbriquées. Dans les versions
précédentes de Python, lorsque vous
référenciez une variable dans une fonction imbriquée ou une fonction lambda,
Python recherchait la variable dans l’espace
de noms de la fonction (imbriquée ou lambda) en
cours, puis dans l’espace de noms du module.
Python 2.2 recherche la variable dans
l’espace de noms de la fonction (imbriquée ou
lambda) en cours, puis dans l’espace de
noms de la fonction parente, puis dans l’espace de noms du
module. Python 2.1 peut adopter l'un ou l'autre de ces
comportements, par défaut il fonctionne comme
Python 2.0, mais vous pouvez ajouter la
ligne de code suivante au début de vos modules pour les faire
fonctionner comme avec Python 2.2 :
from __future__ import nested_scopes |
|
A l’aide des fonctions locals et
globals, vous pouvez obtenir la valeur d’une
variable quelconque dynamiquement, en fournissant le nom de la
variable sous forme de chaîne. C’est une fonctionnalité semblable à
celle de la fonction getattr, qui
vous permet d’accéder à une fonction quelconque dynamiquement en
fournissant le nom de la fonction sous la forme d’une chaîne.
|
- 8.6. Formatage de chaînes à l’aide d’un dictionnaire
|
L’utilisation du formatage de chaîne à l’aide d’un dictionnaire
avec locals est une manière pratique de rendre
des expressions de formatage complexes plus lisibles, mais elle a un
prix. Il y a une petite baisse de performance due à l’appel de
locals, puisque locals
effectue une copie de l’espace de noms local.
|
Chapitre 9. Traitement de données XML
- 9.2. Les paquetages
|
Un paquetage est un répertoire pourvu du fichier __init__.py. Le fichier __init__.py définit les attributs et les méthodes du paquetage. Il n'est cependant pas tenu de définir quoi que ce soit; ce peut simplement
être un fichier vide, mais il se doit d'être présent. Et si __init__.py n'existe pas, le répertoire reste un répertoire, pas un paquetage et ne peut ni être importé ni contenir de modules ou de
paquetages imbriqués.
|
- 9.6. Accéder aux attributs d'un élément
|
Cette section peut paraître un peu confuse dans le mesure où des terminologies se recouvrent. Les éléments d'un document XML ont des attributs, mais les objets Python ont aussi des attributs. Lorsque vous analysez un document XML, vous obtenez un paquet d'objets Python qui représentent l'ensemble des parties du document XML et certains de ces objets Python représentent les attributs des éléments XML. Mais les objets (Python) qui représentent les attributs (XML) possèdent également des attributs (Python), qui sont utilisés pour accéder à diverses parties de l'attribut (XML) que l'objet représente. Je vous avais bien dit que tout cela prêtait à confusion. Je suis ouvert à toute suggestion qui
permettrait de les distinguer plus clairement.
|
|
A l'instar d'un dictionnaire, les attributs d'un élément XML ne sont pas ordonnés. Il se peut que les attributs apparaissent dans un certain ordre dans le document XML original et qu'ils apparaissent dans un certain ordre quand le document XML est analysé en objets Python, mais ces ordonnancements sont arbitraires et n'ont aucune signification particulière. Vous devriez toujours accéder aux
attributs individuels par leur nom, comme les clés d'un dictionnaire.
|
Chapitre 10. Des scripts et des flots de données (streams)
Chapitre 11. Services Web HTTP
- 11.6. Prise en charge de Last-Modified et ETag
|
Dans ces exemples, le serveur HTTP supporte à la fois les en-têtes Last-Modified et ETag, mais ce n'est pas le cas de tous les serveurs. Pour vos clients de services Web, vous devez prévoir de supporter les deux
et programmer de manière défensive au cas ou un serveur ne supporterais que l'un des deux, ou aucun.
|
Chapitre 12. Services Web SOAP
Chapitre 13. Tests unitaires
Chapitre 14. Ecriture des tests en premier
- 14.3. roman.py, étape 3
|
La chose la plus importante que des tests unitaires complets
vous disent est quand vous arrêter d’écrire du code. Quand tous les
tests unitaires d’une fonction passent, arrêtez d’écrire le code de la
fonction. Quand tous les tests d’un module passent, arrêtez d’écrire
le code du module.
|
- 14.5. roman.py, étape 5
|
Quand tous vos tests passent, arrêtez d’écrire du code. |
Chapitre 15. Refactorisation
- 15.3. Refactorisation
|
A chaque fois que vous allez utiliser une expression régulière
plus d’une fois, il vaut mieux la compiler pour obtenir un objet motif
et appeler ses méthodes directement.
|
Chapitre 16. Programmation fonctionnelle
Chapitre 17. Fonctions dynamiques
Chapitre 18. Ajustements des performances
- 18.2. Utilisation du module timeit
|
Vous pouvez utiliser le module timeit en ligne de commande pour tester un programme Python existant sans en modifier le code. Voir http://docs.python.org/lib/node396.html pour la documentation des paramètres de ligne de commande.
|
|
Le module timeit ne fonctionne que si vous savez déjà quelle partie de votre code optimiser. Si vous avez un programme Python plus grand et que vous ne savez pas où se trouve le problème de performances, allez voir le module hotshot. |