In [ ]:
from __future__ import print_function
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.
Peut-être l’instruction la plus connue est-elle l’instruction if
. Par exemple :
In [6]:
x = int(input("Entrez un entier : "))
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')
In [10]:
x="a"
x.isalpha()
Out[10]:
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.
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 (une liste ou une chaîne), dans l’ordre où ils apparaissent dans la séquence. Par exemple :
In [11]:
# Mesurer quelques chaînes de caractères:
liste = ['plat', 'végane', 'manger']
for element in liste:
print (element, len(element), end=', ')
Il n’est pas prudent de modifier la séquence sur laquelle on itère dans la boucle (cela peut seulement arriver pour les types de séquences modifiables, tels que 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 cela particulièrement pratique :
In [ ]:
for x in liste[:]: # fait une copie de la liste entière par découpage
if len(x) > 8: liste.insert(0, x)
print (liste)
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 :
In [12]:
range(10) # équivalent à [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Out[12]:
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) :
In [8]:
range(5, 10) # [5, 6, 7, 8, 9]
Out[8]:
In [16]:
range(0, 10, 2) # [0, 2, 4, 6, 8]
Out[16]:
In [ ]:
range(10, -20, -5) # [10, 5, 0, -5, -10, -15]
Habituellement, on combine for
et range
de la façon suivante :
In [13]:
liste = ['plat', 'végane', 'manger']
for i in range(0, 3, 1): # comme for (i=0; i<3; i++)
print (liste[i], "est l'élément d'indice", i)
Pour parcourir les indices d’une séquence, combinez range()
et len()
comme ci-dessous :
In [14]:
fable = ['Le', 'Lion', 'et', 'le', 'Moucheron']
for i in range(len(fable)):
print ("L'élément d'indice", i, 'est', fable[i])
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
. Cela est expliqué dans la boucle suivante, qui recherche des nombres premiers :
In [11]:
for n in range(2, 10):
for x in range(2, n):
if n % x == 0:
print (n, 'égale', x, '*', n//x) # // est la division entière
break
else:
# la boucle s'est terminée sans trouver facteur
print (n, 'est un nombre premier')
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 :
In [ ]:
n = -10
if n > 0:
pass
else:
print ('Attention n est négatif')
Nous pouvons créer une fonction qui écrit la série de Fibonacci jusqu’à une limite quelconque :
In [16]:
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, end=' ')
a, b = b, a+b
# Maintenant on appelle la fonction qui vient juste d’être définie
fib(1000)
Si on veut tester que l'utilisateur rentre bien un nombre, nous pouvons écrire :
In [17]:
def fib(n): # écrit la série de Fibonacci jusqu’à n
"""Affiche une suite de Fibonacci jusqu'à n."""
if type(n) != int:
print (n, "n'est pas un entier")
return
a, b = 0, 1
while b < n:
print (b, end=' ')
a, b = b, a+b
print()
# Maintenant on appelle la fonction qui vient juste d’être définie
fib(1000000)
fib('toto')
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.
In [18]:
fib?
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. Quand 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. Cela permet de disposer d’un mécanisme général de renommage :
In [14]:
type(fib)
Out[14]:
In [15]:
f = fib
f(100)
Nous pourrions noter 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 :
In [ ]:
print (fib(0))
Écrire une fonction qui retourne une liste des nombres de la suite de Fibonacci, au lieu de les imprimer, est très simple :
In [20]:
def fib2(n): # retourne la série de Fibonacci jusqu’à n
"""Retourne une liste contenant la série de Fibonacci jusqu'à n."""
resultat = list()
a, b = 0, 1
while b < n:
resultat.append(b) # voir ci-dessous
a, b = b, a+b
return resultat
f100 = fib2(100) # Appel de la fonction
print (f100) # Affichage du résultat
print (f100[-1]) # le dernier élément de la série avant 100
Cet exemple, comme d’habitude, démontre quelques nouvelles caractéristiques de Python :
return
termine une fonction en renvoyant une valeur. return
sans une expression en argument renvoie None
. Parvenir jusqu’au bout de la procédure renvoie également None
.resultat.append(b)
appelle une méthode de l’objet resultat
. 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, mais cela sort du cadre de ce cours.) 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 à resultat = resultat + [b]
, mais en plus performant.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.
La technique la plus utile consiste à spécifier une valeur par défaut pour un ou plusieurs arguments. Cela crée une fonction qui peut être appelée avec moins d’arguments qu’il n’en a été défini.
In [23]:
def demande_ok(question, tentatives=3, plainte='Oui ou non, svp!'):
while 1:
ok = 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 refuse')
print (plainte)
# Cette fonction peut être appelée soit comme ceci :
demande_ok('Etes vous sûr de vouloir quitter ?')
# ou comme ceci
demande_ok('OK pour écrasement du fichier ?', 2, 'êtes-vous sûr?')
Out[23]:
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:
In [ ]:
i=5
def f (arg = i):
print (arg)
i = 6
f()
Avertissement important (**) : La valeur par défaut est évaluée seulement une fois. Cela 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 :
In [ ]:
def f(a, L=[]):
L.append(a)
return L
print (f(1))
print (f(2))
print (f(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 :
In [ ]:
def f(a, L=None):
if L is None:
L = []
L.append(a)
return L
Les fonctions peuvent aussi être appelées en utilisant des arguments mots-clés de la forme motcle = valeur
. Par exemple, la fonction suivante :
In [ ]:
def mafonc(x, p=2, debug=False):
"""
Calcule x à la puissance p. p vaut 2 par défaut.
"""
if debug:
print("evaluation de mafonc pour x = " + str(x) +
" en utilisant comme exposant p = " + str(p))
return x**p
pourrait être appelée de l'une des façon suivante:
In [ ]:
print ('Le résultat est :', mafonc(5))
In [ ]:
mafonc(5, 3, False)
In [ ]:
mafonc(5, debug=True)
In [ ]:
mafonc(p=3, debug=True, x=7)
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.
In [ ]:
def function(a):
pass
function(0, a=0)
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. Cela 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 :
In [ ]:
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)
cles = motcles.keys()
cles.sort()
for mc in cles : print (mc, ':', motcles[mc])
qui pourrait être appelée comme ceci:
In [ ]:
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')
Notez que la méthode sort()
de la liste de des mots-clés des noms d’arguments est appelée avant d’imprimer le contenu du dictionnaire motcles ; si cela n’est pas fait, l’ordre dans lequel les arguments sont imprimés n’est pas défini.
La situation inverse se produit lorsque les arguments sont dans une liste ou un n-uplet mais doivent être déballés en vue d’une fonction qui requiert des arguments positionnels séparés. Par exemple, la fonction intégrée range()
attend deux arguments séparés start
et stop
. Si ces derniers ne sont pas disponibles séparément, écrivez l’appel de la fonction avec l’opérateur *
afin de déballer les arguments depuis une liste ou un n-uplet :
In [ ]:
range(3, 6) # appel normal avec des arguments séparés
In [ ]:
args = [3, 6]
range(*args) # appel avec des arguments déballés depuis une liste
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 syntaxi- quement à 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 peuvent faire référence à des variables de la portée qui les contient :
In [ ]:
def fabrique_incrementeur(n):
return lambda x, incr=n: x+incr
f = fabrique_incrementeur(42)
f(0)
In [ ]:
f(1)
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. Cela 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 :
In [ ]:
def ma_fonction():
"""Ne fait rien, mais le documente.
Non, vraiment elle ne fait rien.
"""
pass
print (ma_fonction.__doc__)
ma_fonction?
help(ma_fonction)
Ce notebook est une adaptation de la traduction française, dirigée par Olivier Berger et mise à jour par Henri Garreta, du tutoriel Python édité par Guido van Rossum et Fred L. Drake.