II. Votre premier programme Python▲
La plupart des autres livres expliquent pas à pas les concepts de programmation pour vous amener à la fin à l'écriture d'un programme complet et fonctionnel. Et bien nous allons sauter toutes ces étapes.
II-A. Plonger▲
Voici un programme Python complet et fonctionnel.
Il ne signifie probablement rien pour vous. Ne vous en faites pas, nous allons le disséquer ligne par ligne. Mais lisez-le et voyez ce que vous pouvez déjà en retirer.
Exemple 2.1. odbchelper.py▲
Si vous ne l'avez pas déjà fait, vous pouvez télécharger cet exemple ainsi que les autres exemples du livre
def buildConnectionString(params):
"""Build a connection string from a dictionary of parameters.
Returns string."""
return
";".join(["%s=%s" % (k, v) for k, v in params.items()])
if
__name__ == "__main__":
myParams = {"server":"mpilgrim", \
"database":"master", \
"uid":"sa", \
"pwd":"secret" \
}
print buildConnectionString(myParams)
Lancez maintenant ce programme et observez ce qui se passe.
- Dans l'IDE ActivePython sous Windows, vous pouvez exécuter le programme Python que vous êtes en train d'éditer par File->Run... (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 Python->Run window... (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 «Run as __main__» 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
La sortie de odbchelper.py ressemblera à l'écran suivant :
server=mpilgrim;uid=sa;database=master;pwd=secret
II-B. Déclaration de fonctions▲
Python dispose de fonctions comme la plupart des autre langages, mais il n'a pas de fichiers d'en-tête séparés comme C++ ou de sections interface/implementation comme Pascal. Lorsque vous avez besoin d'une fonction, vous n'avez qu'à la déclarer et l'écrire.
def buildConnectionString(params):
Il y a plusieurs remarques à faire. Premièrement, le mot clé def débute une déclaration de fonction, suivi du nom de la fonction, puis des arguments entre parenthèses. Les arguments multiples (non montré ici) sont séparés par des virgules.
Deuxièmement, la fonction ne défini pas le type de données qu'elle retourne. Les fonctions Python ne définissent pas le type de leur valeur de retour, elle ne spécifient même pas si elle retournent une valeur ou pas. En fait chaque fonction Python retourne une valeur, si la fonction exécute une instruction return, elle va en retourner la valeur, sinon elle retournera None, la valeur nulle en Python.
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.
Troisièmement, les arguments, params, ne spécifient pas de types de données. En Python, les variables ne sont jamais explicitement typées. Python détermine le type d'une variable et en garde la trace en interne.
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.
II-B-1. Comparaison des types de données en Python et dans d'autres langages de programmation▲
Un lecteur érudit propose l'explication suivante pour comparer Python et les autres langages de programmation :
langage à typage statique
Un langage dans lequel les types sont fixés à la compilation. La plupart des langages à typage statique obtiennent cela en exigeant la déclaration de toutes les variables et de leur type avant leur utilisation. Java et C sont des langages à typage statique.
langage à typage dynamique
Un langage dans lequel les types sont découverts à l'exécution, l'inverse du typage statique. VBScript et Python sont des langages à typage dynamique, ils déterminent le type d'une variable la première fois que vous lui assignez une valeur.
langage fortement typé
Un langage dans lequel les types sont toujours appliqués. Java et Python sont fortement typés. Un entier ne peut être traité comme une chaîne sans conversion explicite
langage faiblement typé
Un langage dans lequel les types peuvent être ignorés, l'inverse de fortement typé. VBScript est faiblement typé. En VBScript, vous pouvez concaténer la chaîne '12' et l'entier 3 pour obtenir la chaîne '123' et traiter le résultat comme l'entier 123, le tout sans faire de conversion explicite.
Python est donc à la fois à typage dynamique (il n'utilise pas de déclaration de type explicite) et fortement typé (une fois qu'une variable a un type, cela a une importance).
II-C. Documentation des fonctions▲
Vous pouvez documenter une fonction Python en lui donnant une chaîne de documentation (doc string).
Exemple 2.2. Définition d'une doc string pour la fonction buildConnectionString▲
def buildConnectionString(params):
"""Build a connection string from a dictionary of parameters.
Returns string."""
Les tripes guillemets indiquent une chaîne multi-lignes. Tout ce qu'il y a entre l'ouverture et la fermeture des guillemets fait partie de la chaîne, y compris les retours chariot et les autres guillemets. On peut les utiliser partout, mais vous les verrez le plus souvent utilisées pour définir une doc string.
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.
Tout ce qui se trouve entre les triples guillemets fait partie de la doc string de la fonction, qui décrit ce que fait la fonction. Une doc string, si elle existe, doit être la première chose déclarée dans une fonction (la première chose après les deux points). Techniquement parlant, vous n'êtes pas obligés de donner une doc string à votre fonction, mais vous devriez toujours le faire. Je sais que vous avez entendu cela à tous les cours de programmation auxquels vous avez assisté mais Python vous donne une motivation supplémentaire : la doc string est disponible à l'exécution en tant qu'attribut de fonction.
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.
Pour en savoir plus sur la documentation des fonctions
- La PEP 257 définit les conventions pour les doc string.
- Le Python Style Guide explique la manière d'écrire de bonnes doc string.
- Le Python Tutorial traite des conventions d'espacement dans les doc string.
II-D. Tout est objet▲
Au cas ou vous ne l'auriez pas noté, je viens de dire que les fonctions Python ont des attributs et que ces attributs étaient disponibles au moment de l'exécution.
Une fonction, comme tout le reste en Python, est un objet.
Ouvrez votre IDE Python favorite et suivez ces étapes :
Exemple 2.3. Accéder à la doc string de la fonction buildConnectionString▲
>>> import odbchelper ***1***
>>> params = {"server":"mpilgrim", "database":"master", "uid":"sa", "pwd":"secret"}
>>> print odbchelper.buildConnectionString(params) ***2***
server=mpilgrim;uid=sa;database=master;pwd=secret
>>> print odbchelper.buildConnectionString.__doc__ ***3***
Build a connection string from a dictionary
Returns string.
***1*** La première ligne importe le programme odbchelper comme module -- un morceau de code qui peut être utilisé interactivement ou depuis un programme Python (vous verrez des exemples de programmes Python multimodules au Chapitre 4). Une fois que vous importez un module, vous pouvez référencer chacune de ses fonctions, classes ou attributs publics. Les modules peuvent faire cela pour accéder aux fonctionnalités offertes par d'autres modules et vous pouvez le faire dans l'IDE également. C'est un concept important et nous allons en discuter plus amplement plus tard. ***2*** Quand vous souhaitez utiliser des fonctions définies dans un module importé, vous devez inclure le nom du module. Vous ne pouvez donc pas dire buildConnectionString, ce doit être odbchelper.buildConnectionString. Si vous avez utilisé des classes en Java, cela devrait vous sembler vaguement familier. ***3*** Plutôt que d'appeler la fonction comme vous l'auriez attendu, nous demandons un des attributs de la fonction, __doc__.
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.
II-D-2. Le chemin de recherche d'import▲
Avant d'aller plus loin, je veux mentionner rapidement le chemin de recherche de bibliothèques. Python cherche dans plusieurs endroits lorsque vous essayez d'importer un module. Plus précisément, il regarde dans tous les répertoires définis dans sys.path. C'est une simple liste et vous pouvez facilement la voir ou la modifier à l'aide des méthodes standard de listes (nous en apprendrons plus sur les listes plus loin dans ce chapitre).
Exemple 2.4. Chemin de recherche d'import▲
>>> import sys ***1***
>>> sys.path ***2***
[''
, '/usr/local/lib/python2.2'
, '/usr/local/lib/python2.2/plat-linux2'
,
'/usr/local/lib/python2.2/lib-dynload'
, '/usr/local/lib/python2.2/site-packages'
,
'/usr/local/lib/python2.2/site-packages/PIL'
, '/usr/local/lib/python2.2/site-packages/piddle'
]
>>> sys ***3***
<module 'sys'
(built-in)>
>>> sys.path.append('/my/new/path'
) ***4***
***1*** Importer le module sys rend toutes ses fonctions et attributs disponibles. ***2*** sys.path est une liste de répertoires qui constitue le chemin de recherche actuel (le votre sera différent en fonction de votre système d'exploitation, la version de Python que vous utilisez et l'endroit où vous l'avez installé). Python recherchera dans ces repertoires (dans l'ordre donné) un fichier .py portant le nom de module que vous tentez d'importer. ***3*** En fait j'ai menti, la réalité est plus compliquée que ça car tous les modules ne sont pas dans des fichiers .py. Certains, comme le module sys, sont des modules intégrés, il sont inclus dans Python lui-même. Les modules intégrés se comportent comme des modules ordinaires, mais leur code source Python n'est pas disponible car il ne sont pas écrits en Python (le module sys est écrit en C). ***4*** Vous pouvez ajouter un nouveau répertoire au chemin de recherche de Python en le joignant à sys.path et Python cherchera dans ce répertoire également lorsque vous essayez d'importer un module. Cela dure tant que Python tourne (nous reparlerons de append (joindre) et des autres méthodes de listes au Chapitre 3).
II-D-3. Qu'est-ce qu'un objet ?▲
En Python, tout est objet et presque tout dispose d'attributs et de méthodes. Toutes les fonctions ont un attribut prédéfini __doc__ qui retourne la doc string définie dans le code source de la fonction. Le module sys est un objet qui a (entre autres choses) un attribut appelé path. Et ainsi de suite.
Reste la question : qu'est-ce qu'un objet ? Chaque langage de programmation définit le terme «objet» à sa manière. Pour certain, cela signifie que tout objet doit avoir des attributs et des méthodes, pour d'autres, cela signifie que tout les objets doivent être dérivables. En Python, la définition est plus flexible. Certains objets n'ont ni attributs ni méthodes (nous verrons cela au Chapitre 3) et tous les objets ne sont pas dérivables (voir le Chapitre 5). Mais tout est objet dans le sens où tout peut être assigné à une variable ou passé comme argument à une fonction (voir au Chapitre 4).
Ceci est important et il ne fait aucun mal de le souligner une derniere fois: en Python tout est objet. Les chaînes sont des objets. Les listes sont des objets. Les fonctions sont des objets. Même les modules sont des objets.
Pour en savoir plus sur les objets
- La Python Reference Manual explique précisémment ce qu'implique de dire que tout est objet en Python, puisque certains pédants aiment discuter longuement de ce genre de choses.
- eff-bot propose un résumé des objets Python.
II-E. Indentation du code▲
Les fonctions Python n'ont pas de begin ou end explicites, ni d'accolades qui pourraient marquer là ou commence et ou se termine le code de la fonction. Le seul délimiteur est les deux points («:») et l'indentation du code lui-même.
Exemple 2.5. Indentation de la fonction buildConnectionString▲
def buildConnectionString(params):
"""Build a connection string from a dictionary of parameters.
Returns string."""
return
";".join(["%s=%s" % (k, v) for k, v in params.items()])
Les blocs de code (fonctions, instructions if, boucles for ou while etc.) sont définis par leur indentation. L'indentation démarre le bloc et la désindendation le termine. Il n'y a pas d'accolades, de crochets ou de mots clés spécifiques. Cela signifie que les espaces blancs sont significatifs et qu'ils doivent être cohérents. Dans cet exemple, le code de la fonction (y compris sa doc string) sont indentés de 4 espaces. Cela ne doit pas être forcément 4 espaces, mais il faut que ce soit cohérent. La première ligne non indentée est en dehors de la fonction.
L'Exemple 2.6, «Instructions if» montre un exemple d'indentation du code avec des instructions if.
Exemple 2.6. Instructions if▲
def
fib
(
n): ***
1
***
print
'n ='
, n ***
2
***
if
n >
1
: ***
3
***
return
n *
fib
(
n -
1
)
else
: ***
4
***
print
'end of the line'
return
1
***1*** Voici une fonction nommée fib qui prend un argument, n. Tout le code de cette fonction est indenté.
***2*** Afficher une sortie à l'écran est très facile en Python, il suffit d'utiliser print. Les instructions print peuvent prendre n'importe quel type de données, y compris les chaînes, les entiers et d'autres types prédéfinis comme les dictionnaires et les listes, que vous découvrirez dans le prochain chapitre. Vous pouvez même mélanger les types pour imprimer plusieurs éléments sur la même ligne en utilisant une liste de valeurs séparées par des virgules. Chaque valeur est affichée sur la même ligne, séparée par des espaces (les virgules ne sont pas imprimées). Donc, lorsque fib est appelé avec 5, cette ligne affichera "n = 5".
***3*** Les instructions if sont un type de bloc de code. Si l'expression if est évaluée à vrai, le bloc de code indenté est exécuté, sinon on saute au bloc else.
***4*** Bien sûr, les blocs if et else peuvent contenir des lignes multiples, tant qu'elles sont toutes indentées au même niveau. Ce bloc Ce bloc else contient deux lignes de code. Il n'y a pas d'autre syntaxe pour les blocs de codes multilignes. Indentez et c'est tout.
Après quelques protestations initiales et des analogies méprisantes à Fortran, vous vous en accomoderez et commencerez à en voir les bénéfices. Un des bénéfices majeurs est que tous les programmes Python ont la même apparence puisque l'indentation est une caractéristique du langage et non une question de style. Cela rend plus simple à comprendre le code Python des autres.
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.
Pour en savoir plus sur l'indentation du code
- La Python Reference Manual discute des aspects multiplate-formes de l'indentation etprésente diverses erreurs d'indentation.
- Le Python Style Guide discute du bon usage de l'indentation.
II-F. Test des modules▲
Les modules Python sont des objets et ils ont de nombreux attributs utiles. C'est un aspect que vous pouvez utiliser pour tester facilement vos modules au cours de leur écriture. Voici un exemple qui utilise l'astuce if __name__.
if
__name__
==
"__main__"
:
Quelques remarques avant de passer aux choses sérieuses. Premièrement, les parenthèses ne sont pas obligatoires autour de l'expression if. Ensuite, l'instruction if se termine par deux points et est suivie de code indenté.
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.
En quoi cette instruction if est-elle une astuce ? Les modules sont des objets et tous les modules disposent de l'attribut prédéfini __name__. Le __name__ d'un module dépend de la façon dont vous l'utilisez. Si vous importez le module, son __name__ est le nom de fichier du module sans le chemin d'accès ni le suffixe. Mais vous pouvez aussi lancer le module directement en tant que programme, dans ce cas __name__ va prendre par défaut une valeur spéciale, __main__.
>>>
import
odbchelper
>>>
odbchelper.__name__
'odbchelper'
Sachant cela, vous pouvez concevoir une suite de tests pour votre module au sein même de ce dernier en la plaçant dans ce if. Quand vous lancez le module directement, __name__ est __main__ et la séquence de tests s'exécute. Quand vous importez le module, __name__ est autre chose et les tests sont ignorés. Cela facilite le développement et le déboguage de nouveaux modules avant leur intégration dans un programme plus grand.
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 Run as __main__ est coché.
Pour en savoir plus sur l'importation des modules
- LaPython Reference Manual explique les détails techniques de l'importation de modules.