Sous-sections
4. D'Autres Outils de Contrôle d'Exécution
A part l'instruction while que l'on vient de
découvrir, Python comprend les instructions de contrôle d'exécution
habituelles connues dans d'autres langages, avec quelques
adaptations.
4.1 Instructions if
Peut-être l'instruction la plus connue est-elle l'instruction if.
Par exemple:
>>> if x < 0:
... x = 0
... print 'Négatif changé en zéro'
... elif x == 0:
... print 'Zéro'
... elif x == 1:
... print 'Un seul'
... else:
... print 'Plus'
...
Il peut y avoir aucune ou plusieurs sections elif, et la
section else est optionnelle. Le mot-clé `elif'
est une abréviation de `else if', et est utile pour éviter une
indentation excessive. Une séquence if ...
elif ... elif ... est un substitut pour
les instructions switch ou
case qu'on trouve dans d'autres langages.
4.2 Instructions for
L'instruction for en Python diffère un petit peu de ce que
vous avez pu utiliser en C ou en Pascal. Au lieu d'itérer
toujours dans une progression arithmétique de nombres (comme en
Pascal), ou de laisser l'utilisateur complètement libre dans les tests
et les pas d'itération (comme en C), l'instruction for de
Python itère parmi les éléments de n'importe quelle séquence (par ex.,
une liste ou une chaîne), dans l'ordre où ils apparaissent dans la
séquence. Par exemple (aucun jeu de mots volontaire):
>>> # Mesurer quelques chaînes:
... a = ['chat', 'fenêtre', 'défenestrer']
>>> for x in a:
... print x, len(x)
...
chat 4
fenêtre 7
défenestrer 11
Il n'est pas prudent de modifier la séquence sur laquelle on itère dans la
boucle (ceci peut seulement arriver pour les types de séquences
modifiables, par exemple, les listes). Si vous avez besoin de modifier
la liste sur laquelle vous itérez, par exemple, pour dupliquer des
éléments sélectionnés, vous devez itérer sur une copie. La notation de
découpage rend ceci particulièrement pratique:
>>> for x in a[:]: # fait une copie de la liste entière par découpage
... if len(x) > 8: a.insert(0, x)
...
>>> a
['défenestrer', 'chat', 'fenêtre', 'défenestrer']
4.3 La Fonction range()
Si vous avez besoin d'itérer sur une séquence de nombres, la fonction
intégrée range() vient à point. Elle génère des listes
contenant des progressions arithmétiques, par ex.:
>>> range(10)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Le nombre de fin qui lui est passé n'est jamais dans la liste générée;
range(10) génère une liste de 10 valeurs, exactement les
indices des éléments d'une séquence de longueur 10. Il est possible de
faire commencer l'intervalle à un autre nombre, ou de spécifier un
incrément différent (même négatif):
>>> range(5, 10)
[5, 6, 7, 8, 9]
>>> range(0, 10, 3)
[0, 3, 6, 9]
>>> range(-10, -100, -30)
[-10, -40, -70]
Pour parcourir les indices d'une séquence, combinez range()
et len() comme ci-dessous:
>>> a = ['Marie', 'avait', 'un', 'petit', 'mouton']
>>> for i in range(len(a)):
... print i, a[i]
...
0 Marie
1 avait
2 un
3 petit
4 mouton
4.4 Les Instructions break et continue, et les Clauses else dans les Boucles
L'instruction break, comme en C, sort de la plus petite
boucle for ou while englobante.
L'instruction continue, également empruntée au C,
continue sur la prochaine itération de la boucle.
Les instructions de boucle ont une clause else ; elle est
exécutée lorsque la boucle se termine par épuisement de la liste (avec
for) ou quand la condition devient fausse (avec
while), mais pas quand la boucle est interrompue par une
instruction break. Ceci est expliqué dans la boucle
suivante, qui recherche des nombres premiers:
>>> for n in range(2, 10):
... for x in range(2, n):
... if n % x == 0:
... print n, 'égale', x, '*', n/x
... break
... else:
... print n, 'est un nombre premier'
...
2 est un nombre premier
3 est un nombre premier
4 égale 2 * 2
5 est un nombre premier
6 égale 2 * 3
7 est un nombre premier
8 égale 2 * 4
9 égale 3 * 3
4.5 L'Instruction pass
L'instruction pass ne fait rien. Elle peut être utilisée
lorsqu'une instruction est requise syntaxiquement mais que le programme
ne nécessite aucune action.
Par exemple:
>>> while 1:
... pass # Attente active d'une interruption au clavier
...
4.6 Définition de Fonctions
Nous pouvons créer une fonction qui écrit la série de Fibonacci
jusqu'à une limite quelconque:
>>> def fib(n): # écrit la série de Fibonacci jusqu'à n
... "Affiche une suite de Fibonacci jusqu'à n"
... a, b = 0, 1
... while b < n:
... print b,
... a, b = b, a+b
...
>>> # Maintenant on appelle la fonction qui vient juste d'être définie
... fib(2000)
1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597
Le mot-clé def débute la définition d'une
fonction. Il doit être suivi par le nom de la fonction et une liste
entre parenthèses de paramètres formels. Les instructions qui forment
le corps de la fonction commencent sur la ligne suivante, indentée par
une tabulation. La première instruction du corps de la fonction peut
éventuellement être un texte dans une chaîne de caractères; cette
chaîne est la chaîne de documentation de la fonction, ou
docstring.
Il y a des outils qui utilisent les docstrings pour
générer automatiquement de la documentation papier, ou pour permettre
à l'utilisateur de naviguer interactivement dans le code; c'est une
bonne technique que d'inclure les docstrings dans le code que vous
écrivez, donc essayez de vous y habituer.
L'exécution d'une fonction génère une nouvelle table de symboles,
utilisée pour les variables locales de la fonction. Plus précisément,
toutes les affectations de variables dans une fonction stockent la
valeur dans la table de symboles locale; alors que les références à
des variables regardent en premier dans la table de symboles locale,
puis dans la table de symboles globale, et enfin dans la table des
noms intégrés. Ainsi, on ne peut affecter directement une valeur aux
variables globales à l'intérieur d'une fonction (à moins de les déclarer
avec une instruction global), bien qu'on puisse y faire
référence.
Les vrais paramètres (arguments) d'un appel de fonction sont
introduits dans la table de symboles locale de la fonction appelée
quand elle est appelée; ainsi, les arguments sont passés en utilisant
un passage par valeur.4.1Quand une fonction appelée appelle à son tour une autre fonction, une nouvelle
table de symboles locaux est créée pour cet appel.
La définition d'une fonction introduit le nom de la fonction dans la
table de symboles courante. La valeur du nom de la fonction a un type
qui est reconnu par l'interpréteur comme une fonction définie par
l'utilisateur. Cette valeur peut être affectée à un autre nom qui peut
alors être utilisé aussi comme une fonction. Ceci permet de disposer
d'un mécanisme général de renommage:
>>> fib
<function object at 10042ed0>
>>> f = fib
>>> f(100)
1 1 2 3 5 8 13 21 34 55 89
Vous pourriez objecter que fib n'est pas une fonction mais une
procédure. En Python, comme en C, les procédures sont juste des
fonctions qui ne retournent pas de valeur. En fait, techniquement
parlant, les procédures retournent bien une valeur, bien qu'elle soit
plutôt décevante. Cette valeur est appelée None (c'est un nom
intégré). La valeur None n'est normalement pas affichée par
l'interpréteur si elle devait être la seule valeur écrite. Vous pouvez
le vérifier si vous y tenez vraiment:
>>> print fib(0)
None
Ecrire une fonction qui retourne une liste des nombres de la suite de
Fibonacci, au lieu de les imprimer, est très simple:
>>> def fib2(n): # retourne la série de Fibonacci jusqu'à n
... "Retourne une liste contenant la série de Fibonacci jusqu'à n"
... resultat = []
... a, b = 0, 1
... while b < n:
... resultat.append(b) # voir ci-dessous
... a, b = b, a+b
... return resultat
...
>>> f100 = fib2(100) # on l'appelle
>>> f100 # écrire le résultat
[1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]
Cet exemple, comme d'habitude, démontre quelques nouvelles
caractéristiques de Python:
- L'instruction return termine une fonction en renvoyant une
valeur. return sans une expression en argument est utilisé
pour retourner depuis le milieu d'une procédure (aboutir à la fin
termine aussi la procédure), auquel cas la valeur
None
est retournée.
- L'instruction
result.append(b) appelle une méthode de
l'objet result . Une méthode est une fonction qui
`appartient' à un objet et est nommée obj.nommethode , où
obj est un objet (cela pourrait être une expression), et
nommethode est le nom d'une méthode qui est définie d'après
le type de l'objet. Différents types définissent différentes
méthodes. Les méthodes de types différents peuvent avoir le même nom
sans que cela soit source d'ambiguïtés. (Il est possible de définir
vos propres types d'objets et méthodes, en utilisant des
classes, de la façon décrite en 9.) La
méthode append() montrée précédemment, est définie
pour les objets listes; elle ajoute un nouvel élément à la fin de la
liste. Dans cet exemple, c'est équivalent à "result = result +
[b]", mais en plus performant.
4.7 Encore Plus sur la Définition de Fonctions
Il est aussi possible de définir des fonctions à nombre
d'arguments variable. Il y a trois façons de faire, qui peuvent être
combinées.
4.7.1 Valeurs d'Argument par Défaut
La technique la plus utile consiste à spécifier une valeur par défaut pour un
ou plusieurs arguments. Ceci crée une fonction qui peut être appelée
avec moins d'arguments qu'il n'en a été défini, par ex.
def demande_ok(question, tentatives=4, plainte='Oui ou non, svp!'):
while 1:
ok = raw_input(question)
if ok in ('o', 'ou', 'oui'): return 1
if ok in ('n', 'no', 'non', 'niet'): return 0
tentatives = tentatives - 1
if tentatives < 0: raise IOError, 'utilisateur refusenik'
print plainte
Cette fonction peut être appelée soit comme ceci:
demande_ok('Etes vous sûr de vouloir quitter?') 4.2 ou comme ceci:
demande_ok('OK pour écrasement du fichier?', 2) .
Les valeurs par défaut sont évaluées au moment de la définition de la fonction dans la portée de définition, ainsi par ex.
i = 5
def f(arg = i): print arg
i = 6
f()
affichera 5 .
Avertissement important: La valeur par défaut est évaluée
seulement une fois. Ceci est important lorsque la valeur par
défaut est un objet modifiable comme une liste ou un dictionnaire. Par
exemple, la fonction suivante accumule les arguments qui lui sont
passés au fur et à mesure des appels:
def f(a, l = []):
l.append(a)
return l
print f(1)
print f(2)
print f(3)
Ceci affichera
[1]
[1, 2]
[1, 2, 3]
Si vous ne voulez pas que la valeur par défaut soit partagée entre des
appels successifs, vous pouvez plutôt écrire la fonction comme ceci:
def f(a, l = None):
if l is None:
l = []
l.append(a)
return l
4.7.2 Arguments à Mot-Clé
Les fonctions peuvent aussi être appelées en utilisant des arguments
mots-clés de la forme "motcle = valeur". Par exemple,
la fonction suivante:
def perroquet(voltage, etat='c\'est du solide', action='voom', type='Bleu Norvégien'):
print "-- Ce perroquet ne fera pas", action,
print "si vous le mettez sous", voltage, "Volts."
print "-- Beau plumage, le", type
print "-- Ca", etat, "!"
pourrait être appelée de l'une des façons suivantes:
perroquet(1000)
perroquet(action = 'VOOOOOM', voltage = 1000000)
perroquet('un millier', etat = 'fait bouffer les pissenlits par la racine')
perroquet('un milion', 'vous dégoute de la vie', 'de bonds')
mais les appels suivants seraient tous invalides:
perroquet() # manque un argument obligatoire
perroquet(voltage=5.0, 'rend mort') # un argument non-mot-clé suit un mot-clé
perroquet(110, voltage=220) # doublon de valeurs pour un argument
perroquet(acteur='John Cleese') # mot-clé inconnu
En général, une liste d'arguments doit être constituée de tous les
arguments de position, suivis de tous les arguments mots-clés, où ces
mots-clés doivent être choisis parmi les noms des paramètres formels.
Il n'est pas important qu'un paramètre formel ait une valeur par
défaut ou non. Aucun argument ne peut recevoir une valeur plus d'une
fois -- les noms de paramètre formel correspondant aux arguments de
position ne peuvent être utilisés comme mots-clés dans les mêmes
appels.
>>> def function(a):
... pass
...
>>> function(0, a=0)
Traceback (innermost last):
File "<stdin>", line 1, in ?
TypeError: keyword parameter redefined
Quand un paramètre formel de la forme **nom est présent
en dernière position, il reçoit un dictionnaire contenant tous les
arguments mots-clés dont les mots-clés ne correspondent pas à un
paramètre formel. Ceci peut être combiné avec un paramètre formel de
la forme *nom (décrit dans la sous-section suivante) qui
reçoit un tuple contenant les arguments positionnels au-delà de la
liste de paramètres formels. (*nom doit être placé avant
**nom .) Par exemple, nous définissons une fonction comme
ceci:
def fromagerie(type, *arguments, **motcles):
print "-- Avez-vous du", type, '?'
print "-- Je suis désolé, plus personne n'a de", type
for arg in arguments: print arg
print '-'*40
for mc in motcles.keys(): print mc, ':', motcles[mc]
Elle pourrait être appelée comme ceci:
fromagerie('Camembert', "Il est très coulant, monsieur.",
"Il est vraiment très, TRES coulant, monsieur.",
client='John Cleese',
proprietaire='Michael Palin',
sketch='Sketch de la Fromagerie' )
et bien sûr, elle écrirait:
-- Avez-vous du Camembert ?
-- Je suis désolé, plus personne n'a de Camembert
Il est très coulant, monsieur.
Il est vraiment très, TRES coulant, monsieur.
----------------------------------------
client : John Cleese
proprietaire : Michael Palin
sketch : Sketch de la Fromagerie
4.7.3 Listes d'Arguments Arbitraires
Finalement, l'option la moins fréquemment utilisée est de spécifier
qu'une fonction peut être appelée avec un nombre d'arguments
arbitraire. Ces arguments seront récupérés dans un tuple. Avant le
nombre variable d'arguments, zéro ou plus arguments normaux pourraient
être présents.
def fprintf(fichier, format, *args):
fichier.write(format % args)
4.7.4 Les Formes Lambda
Suite à la demande populaire, quelques caractéristiques trouvées
habituellement dans les langages de programmation fonctionnelle et dans
Lisp ont été ajoutées à Python. Avec le mot-clé lambda, de
petites fonctions anonymes peuvent être créées. Voici une fonction qui
retourne la somme de ses deux arguments: "lambda a, b: a+b". Les
formes Lambda peuvent être utilisées chaque fois qu'un objet fonction
est requis. Elles sont limitées syntaxiquement à une expression unique.
Sémantiquement, elles sont juste de l'enrobage syntaxique
pour une définition de fonction normale. Comme les définitions de
fonctions imbriquées, les formes lambda ne peuvent pas faire référence
à des variables de la portée qui les contient, mais ceci peut être
surpassé en utilisant judicieusement les valeurs des arguments par
défaut, par ex.
def fabrique_incrementeur(n):
return lambda x, incr=n: x+incr
4.7.5 Chaînes de Documentation (Docstrings)
Il existe des conventions émergentes à propos du contenu et du
formatage des chaînes de documentation.
La première ligne devrait toujours être un résumé concis des objectifs
de l'objet. Afin d'être bref, il ne devrait pas répéter explicitement
le nom ou le type de l'objet, puisque ces informations sont
disponibles par d'autres moyens (sauf si le nom se trouve être un
verbe décrivant l'utilisation d'une fonction). Cette ligne devrait
toujours commencer par une lettre majuscule et finir par une virgule.
S'il y a d'autres lignes dans la chaîne de documentation, la deuxième
ligne devrait être vide, séparant visuellement le résumé du reste de
la description. Les lignes suivantes devraient constituer un ou
plusieurs paragraphes décrivant les conventions d'appel des objets,
ses effets de bord, etc.
L'interpréteur python ne supprime pas l'indentation des chaînes de
texte multilignes en Python, donc les outils qui traitent la
documentation doivent supprimer l'indentation. Ceci peut se faire en
utilisant la convention suivante. La première ligne non-vide
après la première ligne de la chaîne détermine la
quantité d'indentation pour toute la chaîne de documentation. (On ne
peut pas utiliser la première ligne puisqu'elle est généralement
adjacente aux quotes ouvrantes de la chaîne donc son indentation n'est
pas apparente dans le texte de la chaîne.) Les espaces
``équivalents'' à cette indentation sont ensuite supprimés du début de
toutes les lignes de la chaîne. Des lignes indentées de façon moins
importante ne devraient pas apparaître, mais si elles le font, tous
leurs espaces en début de ligne devraient être supprimés.
L'équivalence de l'espacement devrait être testée après l'expansion des
tabulations (à 8 espaces, normalement).
Voici un exemple de docstring multi-ligne:
>>> def ma_fonction():
... """Ne fait rien, mais le documente.
...
... Non, vraiment, elle ne fait rien.
... """
... pass
...
>>> print ma_fonction.__doc__
Ne fait rien, mais le documente.
Non, vraiment, elle ne fait rien.
Notes
- ... valeur.4.1
- En réalité, passage par référence d'objet serait
une meilleure description, puisque si un objet modifiable est
passé, l'appelant verra tous les changements que l'appelé y
effectue (par ex., des éléments insérés dans une liste).
- ... quitter?')4.2
- NDT : l'accent circomflexe sur le ``u'' de ``sur'' s'affiche assez mal chez nous. Désolé, mais notre compétence en LaTeX est limitée. Merci de nous signaler le correctif.
See About this document... for information on suggesting changes.
|