0% ont trouvé ce document utile (0 vote)
48 vues20 pages

2425 CHAP01 Info

Ce chapitre introduit les bases de la programmation en Python, en se concentrant sur les types simples, les expressions, les variables et les structures de contrôle. Il couvre les types de données tels que les entiers, flottants et booléens, ainsi que les opérations et règles de priorité associées. Les concepts d'identificateurs et d'affectation de variables sont également expliqués, mettant en avant la flexibilité de Python en matière de typage.

Transféré par

adrien.batut
Copyright
© © All Rights Reserved
Nous prenons très au sérieux les droits relatifs au contenu. Si vous pensez qu’il s’agit de votre contenu, signalez une atteinte au droit d’auteur ici.
Formats disponibles
Téléchargez aux formats PDF, TXT ou lisez en ligne sur Scribd
0% ont trouvé ce document utile (0 vote)
48 vues20 pages

2425 CHAP01 Info

Ce chapitre introduit les bases de la programmation en Python, en se concentrant sur les types simples, les expressions, les variables et les structures de contrôle. Il couvre les types de données tels que les entiers, flottants et booléens, ainsi que les opérations et règles de priorité associées. Les concepts d'identificateurs et d'affectation de variables sont également expliqués, mettant en avant la flexibilité de Python en matière de typage.

Transféré par

adrien.batut
Copyright
© © All Rights Reserved
Nous prenons très au sérieux les droits relatifs au contenu. Si vous pensez qu’il s’agit de votre contenu, signalez une atteinte au droit d’auteur ici.
Formats disponibles
Téléchargez aux formats PDF, TXT ou lisez en ligne sur Scribd

Chapitre 01 Informatique

Chapitre 01

PROGRAMMATION EN PYTHON
Ce chapitre présente de manière détaillée les bases de la programmation Python. Il présente tout ce qui est au programme (et
un peu plus), à l’exception de la lecture/écriture dans des fichiers, et les modules usuels, qui feront l’objet d’un chapitre à part.
La version de Python utilisée est Python 3 (toutes les versions 3.x).

1 Types simples et expressions

1.1 Expressions

Une expression est une suite de caractères définissant une valeur. Pour connaître cette valeur, la machine doit évaluer l’ex-
pression. Voici quelques exemples numériques :

>>> 1+4
5
>>> 2.1+7
9.1
>>> 5/2
2.5
>>> 5//2*4.5
9.0

Les valeurs possèdent ce qu’on appelle un type : par exemple entier, flottant, booléen, chaîne de caractères, liste, fonction
. . . Le type détermine les propriétés formelles de la valeur (par exemple, les opérations qu’elle peut subir) et matérielles (par
exemple, la façon dont elle est représentée en mémoire et la place qu’elle occupe). Pour connaître le type d’une expression après
évaluation, il suffit de le demander à Python à l’aide de type :

>>> type(1+4)
<class 'int'>
>>> type(2.1+7)
<class 'float'>
>>> type(5/2)
<class 'float'>
>>> type(4<7)
<class 'bool'>
>>> type("coucou")
<class 'str'>
>>> type([1,1,1])
<class 'list'>
>>> type(lambda x:x**2) # ceci est la fonction qui à x associe x^2
<class 'function'>

On retrouve ici des types simples : entier (int), flottant (float) et booléen (bool). Chacun de ces types va faire l’objet d’un
traitement particulier dans ce qui suit, de même que les types plus compliqués (chaînes de caractères, listes, fonctions...) un peu
plus tard. On ne se préoccupera pas du mot clef class qui fait référence au caractère orienté objet du langage Python.
Comme dans la plupart des langages de programmation, une expression en Python est soit :
— une constante comme 2 ou 3.5 ;
— un nom de variable comme x, i, ou compteur ;
— le résultat d’une fonction appliquée à une ou plusieurs expressions, comme PGCD(5,9) ;
— la composée de plusieurs expressions réunies à l’aide d’opérateurs, comme not a, 3**6, (6+7)*8. Les parenthèses servent
comme en mathématiques à préciser quels opérateurs doivent être évalués en premier. Voyons maintenant les types simples
en détail.

Naïm Touil Page 1/20 Math Sup PTSI Saint-Joseph Toulouse


Chapitre 01 Informatique

1.2 Entiers
Constantes. Il n’y a pas grand chose à dire sur les entiers. On soulignera simplement qu’en Python, les entiers sont non bornés
et permettent donc de faire des calculs exacts, avec des entiers gigantesques.

>>> 5**76 # ** est l'exponentiation


132348898008484427979425390731194056570529937744140625

Opérateurs. Les opérateurs sur les entiers sont précisés dans la liste ci-dessous :

opérateur + - * // % **
signification addition soustraction multiplication division entière modulo exponentiation

On notera bien que // produit une division entière (quotient dans la division euclidienne). On ne peut pas évaluer a//b si
b est nul, et on fera attention si b est négatif ; en effet le comportement est un peu différent de la définition vue en cours
de mathématiques.
Règles de priorité. Certains opérateurs sont évalués avant les autres, dans l’ordre de priorité suivant :
1. Exponentiation.
2. Multiplication, division, modulo.
3. Addition et soustraction.
Sur les opérateurs de même priorité, c’est celui qui est le plus à gauche qui est évalué en premier, à l’exception de l’expo-
nentiation, cohérente avec l’usage en mathématiques. Les parenthèses permettent de changer ces priorités.

>>> 2+25%3*2**4
18
>>> (2+25%(3*2))**4
81
>>> 2**3**2 # devrait donner 64 si la première exponentiation était évaluée en premier
512

1.3 Flottants
Constantes. Les flottants sont représentés en mémoire sur 32 ou 64 bits suivant le système (plutôt 64 de nos jours). Sur 64 bits,
on a 1 bit de signe, 11 bits d’exposant et 52 bits de mantisse (on étudiera en détail la représentation des flottants dans un
cours dédié). On tiendra compte du fait que seul un nombre fini de réels sont représentables en mémoire, ce qui ne permet
pas de faire des calculs exacts. En particulier, le plus petit nombre strictement positif représentable exactement en flottant
sur 64 bits est 2−1074 et le plus grand est légèrement inférieur à 21024 .
Opérateurs. Les opérateurs sur les flottants sont précisés dans la liste ci-dessous (on s’en servira rarement, mais on peut égale-
ment utiliser le modulo . . .) :

opérateur + - * / **
signification addition soustraction multiplication division exponentiation

Règles de priorité. De même que sur les entiers, certains opérateurs sont évalués avant les autres, dans l’ordre de priorité
suivant :
1. Exponentiation.
2. Multiplication, division.
3. Addition et soustraction.
Comme pour les entiers, les opérateurs de même priorité sont évalués de gauche à droite, et les parenthèses permettent de
changer ces priorités.
Conversion automatique. On remarque que la plupart des opérateurs sur les entiers et flottants sont les mêmes. Lorsque l’on
utilise l’un de ces opérateurs avec des entiers et des flottants, les entiers sont automatiquement convertis en flottants (on
pourrait forcer la conversion de l’entier n en flottant avec float(n)). C’est le cas également pour la division flottante
utilisée avec des entiers.

>>> 4*3.1
12.4
>>> 3/4
0.75

Naïm Touil Page 2/20 Math Sup PTSI Saint-Joseph Toulouse


Chapitre 01 Informatique

1.4 Booléens
Constantes. Les booléens sont essentiels en informatique. Ce type comprend uniquement deux constantes : True et False (Vrai
et Faux). Ils sont principalement utilisés dans les structures de contrôle (voir section 3).
Opérateurs. Les opérateurs sur les booléens sont au nombre de trois. L’un (not) est un opérateur unaire (ne prenant qu’un
opérande), les deux autres (and et or) sont des opérateurs binaires (nécessitant deux opérandes). la liste suivante présente
les différents opérateurs booléens et leurs tables de vérité.

a b not a a or b a and b
False False True False False
False True True True False
True False False True False
True True False True True

Ce tableau est intuitif : not correspond à la négation. Pour que a and b soit vrai, il faut que a et b le soient tous les deux.
Pour que a or b soit vrai, il suffit que l’un des deux le soit. Attention : le « ou » français peut parfois avoir le sens d’un ou
exclusif, comme dans « fromage ou dessert ». Le or en informatique est toujours inclusif (si a et b sont vrais, alors a or b
aussi).
Règles de priorité. L’ordre de priorité d’évaluation pour les opérations booléennes est le suivant :

1. not.
2. and.
3. or.

De même que pour les entiers et les flottants, on évalue ensuite de gauche à droite les opérateurs de même priorité, et on
peut user de parenthèses.

>>> False and False or True


True
>>> False and (False or True)
False

Opérateurs de comparaison et booléens. On utilise rarement des booléens tels quels. Leur intérêt réside dans les structures
de contrôle conditionnelles que l’on verra en section 3. Ces structures font beaucoup usage de l’évaluation d’expressions
produisant des booléens, parmi lesquelles on trouve les opérations de comparaisons sur les entiers/flottants :

opérateur == != < <= > >=


signification égal non égal inférieur inférieur ou égal supérieur supérieur ou égal

>>> 4>=3 or 5==0


True

Pour les évaluations des opérateurs binaires, les deux opérandes des opérateurs de comparaisons sont amenés à un type
commun avant l’évaluation de la comparaison (flottant dans le cas d’entier et flottant).
La priorité des opérateurs de comparaison est inférieure à celle des opérateurs arithmétiques : ainsi, l’expression a==b+c
signifie a==(b+c), ce qui est assez logique.
On peut également, comme sur beaucoup d’objets Python, utiliser les opérateurs == et != pour l’égalité et la différence de
booléens. Notons que si x est un booléen, il est parfaitement inutile d’écrire quelque chose comme x==True : ce booléen
est égal à x. De même, on préférera écrire not x que x==False.
Caractère paresseux des opérateurs and et or. On notera que dans une expression de la forme a and b, où a et b sont des
expressions, si a s’évalue en False, on n’a pas besoin d’évaluer b pour s’apercevoir que a and b s’évalue en False. De
même avec a or b si a s’évalue en True. Python respecte cette logique : si la partie gauche suffit à déterminer si l’ex-
pression s’évalue en True ou False, il n’évalue pas la partie droite (on parle du caractère paresseux des opérateurs). C’est
particulièrement utile lors de l’évaluation d’une expression dont la seconde partie pourrait produire une erreur, mais dont
la première sert de garde-fou : x>0 and log(x)>2 ne produit pas d’erreur, même si x est un nombre négatif. En effet, dans
ce cas x>0 s’évalue en False et on n’a pas besoin d’évaluer log(x)>2 qui produirait une erreur, le log n’étant pas défini
sur les nombres négatifs.
Raccourcis. Plutôt que d’écrire a<=b and b<=c, Python comprend très bien a<=b<=c. On n’abusera cependant pas de ces rac-
courcis, pour écrire des choses illisibles comme a<b>=c.

Naïm Touil Page 3/20 Math Sup PTSI Saint-Joseph Toulouse


Chapitre 01 Informatique

2 Variables

2.1 Identificateurs

Un identificateur est une suite de lettres et chiffres, qui commence par une lettre, et qui n’est pas un mot réservé du langage. Les
mots réservés du langage Python sont par exemple if, else, def, return, True . . . Le caractère _ (underscore, ou « tiret du
8 ») est considéré comme une lettre. Ainsi, i, j, x, x2, compteur et taille_de_la_liste sont des identificateurs corrects,
contrairement à 4a, x{}, if ou encore taille de la liste. Les majuscules et minuscules ne sont pas équivalents : x et X
sont des identificateurs distincts. Même si les accents sont autorisés, on veillera à ne pas en mettre dans les identificateurs pour
ne pas faire dépendre la bonne exécution d’un programme de l’encodage des caractères.

2.2 Variables

Une variable est constituée de l’association d’un identificateur à une valeur. Cette association est créée lors de l’affectation,
qui s’écrit sous la forme variable = expression. Attention : il ne faut pas confondre = (affectation) avec == (test d’égalité). Le
mécanisme de l’affectation est le suivant : l’expression à droite du signe égal est évaluée, puis le résultat de l’évaluation est affecté
à la variable. Cela n’a donc rien à voir avec le signe = des mathématiques. À la suite d’une telle affectation, chaque apparition de
la variable ailleurs que dans la partie gauche d’une autre affectation représente la valeur en question. Cette association entre la
variable et la valeur est valable tant qu’il n’y a pas de nouvelle affectation avec cette même variable.

>>> x=2+2 #on évalue 2+2, on obtient 4, qu'on affecte à x.


>>> y=x**x+1 #ici, x représente la valeur 4. 4**4+1 vaut 257, qu'on affecte à y.
>>> print(y-1) #print est une fonction d'affichage. y-1 s'évalue en 256, qu'on affiche.
256
>>> x=y/2 #nouvelle affectation de x.
>>> print(x)
128.5

Comme on le voit sur ces exemples, en Python :


— contrairement à plusieurs autres langages de programmation, les variables n’ont pas besoin d’être déclarées (c’est-à-dire
préalablement annoncées), la première affectation leur tient lieu de déclaration ;
— les variables ne sont pas liées à un type (mais les valeurs auxquelles elles sont associées le sont forcément) : la même
variable x a été associée à des valeurs de types différents (un int, puis un float).
Dans la suite, on confondra allègrement l’identificateur, la variable (l’association de l’identificateur à une valeur) et la valeur
elle-même. Si un identificateur n’a pas été affecté (en toute rigueur il n’est donc pas un nom de variable) son emploi ailleurs que
dans le membre gauche d’une affectation est illégale et provoque une erreur. Par exemple :

>>> print(variable_inconnue)
Traceback (most recent call last):
File "<console>", line 1, in <module>
NameError: name 'variable_inconnue' is not defined

Seul un identificateur correct peut figurer dans le membre gauche d’une affectation. Une syntaxe de la forme x+1=y n’a aucun
sens :

>>> y=5
>>> x+1=y
File "<console>", line 1
x+1=y
^^^
SyntaxError: cannot assign to expression here. Maybe you meant '==' instead of '='?

L’erreur est explicite : on ne peut pas affecter à l’opérateur +. Un mécanisme qui sert souvent en informatique est l’incrémen-
tation d’une variable : on lui rajoute un certain nombre, souvent 1.

>>> x=4
>>> x=x+1 # le signe = n'a rien à voir avec celui des mathématiques !
>>> print(x)
5

Il y a un raccourci en Python pour cette opération : x+=1. On peut de même écrire x-=2 ou encore x/=3.

Naïm Touil Page 4/20 Math Sup PTSI Saint-Joseph Toulouse


Chapitre 01 Informatique

Enfin, lors de l’affectation x=y, la variable x prend la valeur de celle de y (l’évaluation de l’expression y donne simplement la
valeur stockée dans la variable y), mais x et y ne sont pas « liées » pour autant :

>>> y=2
>>> x=y
>>> y=5
>>> print(x)
2

3 Structures de contrôles

3.1 Python et l’indentation

Contrairement à la plupart des autres langages, Python n’utilise pas d’accolades ... ou de mots clefs de la forme begin ...
end pour délimiter des blocs d’instructions : tout est basé sur l’indentation : le fait de laisser une marge blanche devant un bloc
d’instructions. C’est fort pratique pour écrire un code court, mais il faut faire attention à respecter des règles strictes :

— une séquence d’instructions est faite d’instructions écrites avec la même indentation ;
— dans une structure de contrôle (instruction conditionnelle if ou boucles for et while, qu’on va voir tout de suite) ou dans la
définition d’une fonction (voir section 5), une séquence d’instructions subordonnées doit avoir une indentation supérieure
à celle de la séquence englobante. Toute ligne écrite avec la même indentation que cette séquence englobante marque la
fin de la séquence subordonnée.

L’indentation standard est de quatre espaces, ou une tabulation. Les éditeurs intelligents remplacent automatiquement une
tabulation par quatre espaces.

Le point-virgule. Pour éviter de revenir à la ligne systématiquement entre deux instructions, on peut séparer les instructions par
des points virgules, par exemple a=2 ; b=4, qui réalise successivement l’affectation de a puis celle de b.

3.2 Instruction conditionnelle if/else (si/sinon)

La structure générale d’une instruction conditionnelle est la suivante (rappelez-vous, en Python, l’indentation est primordiale).

if expression:
[instructions effectuées si expression s'évalue en True]
elif autre_expression:
[instructions effectuées si expression s'évalue en False et autre_expression en True]
else:
[instructions effectuées si expression et autre_expression s'évaluent en False]

Les expressions utilisées sont des expressions booléennes : leur évaluation doit produire un booléen : True ou False. De
telles expressions sont par exemple a>=4, ou bien not a==0 and b>=2 (a est non nul et b est supérieur ou égal à 2).
Dans une telle structure conditionnelle, les expressions booléennes sont évaluées les unes après les autres, de haut en bas,
jusqu’à ce que l’une d’entre elles s’évalue en True. Le bloc d’instructions correspondant (et seulement celui-ci) est alors exé-
cuté, puis on sort de la structure conditionnelle. Le bloc correspondant au else est exécuté seulement si toutes les expressions
conditionnelles situées au dessus se sont évaluées en False. Il est possible de mettre plusieurs elif.
Voici un exemple, avec note une variable supposée contenir un flottant entre 0 et 20.

if note>=16:
print("Mention Très bien")
elif note>=14:
print("Mention Bien")
elif note>=12:
print("Mention Assez bien")
elif note>=10:
print("Mention Passable")
else:
print("Raté !")

Naïm Touil Page 5/20 Math Sup PTSI Saint-Joseph Toulouse


Chapitre 01 Informatique

Même si note contient un flottant supérieur à 16, on n’affichera à l’écran (effet de la fonction print) qu’une seule ligne : la
première telle que la condition note>=... soit réalisée, ou « Raté ! » si note est strictement inférieure à 10.
elif et else peuvent tous deux être omis. Dans une telle suite d’instructions au plus une (et exactement une si else est
présent) est exécutée : la première telle que l’expression booléenne associée s’évalue en True. Par exemple, dans la séquence
suivante, x est incrémenté de 1 s’il est supérieur ou égal à 2, et divisé par 2 s’il est strictement inférieur à 0.

if x<0:
x=x/2
elif x>=2:
x+=1

Si x appartient à l’intervalle [0 ; 2[, il est inchangé. Il est parfaitement inutile d’écrire quelque chose comme x=x dans un bloc
else.
Prenons un exemple complet un peu plus complexe, la résolution d’une équation polynomiale de degré 2 sur les réels, en
supposant que les variables a, b et c contiennent des flottants, avec a non nul.

Delta=b**2-4*a*c
if Delta<0:
print("Pas de racines !")
elif Delta>0:
r=sqrt(Delta)
x1=(-b-r)/(2*a)
x2=(-b+r)/(2*a)
print("Il y a deux racines distinctes, qui sont: ",x1,"et",x2)
else:
print("Il y a une racine double, qui est: ",-b/(2*a))

On laisse le lecteur se reporter au chapitre sur la représentation des nombres pour la pertinence de l’algorithme lorsque le
discriminant est calculé comme étant zéro.

Écriture en ligne. Il n’est en fait pas obligatoire de faire un saut de ligne après un if, elif ou else, en particulier s’il n’y a
qu’une instruction à écrire. Cela est valable également pour les boucles et les fonctions (voir la suite). Par exemple le code
suivant est équivalent à celui vu plus haut :

if note>=16: print("Mention Très bien")


elif note>=14: print("Mention Bien")
elif note>=12: print("Mention Assez bien")
elif note>=10: print("Mention Passable")
else: print("Raté !")

On peut trouver cela moins clair qu’avec des sauts de ligne, mais on le voit parfois dans les sujets de concours, vous êtes
donc prévenus !

3.3 Boucle conditionnelle while (tant que)

La boucle while permet de réaliser une suite d’instructions tant qu’une certaine condition est vraie. La structure est la suivante.

while expression:
[instructions]

Le mécanisme est le suivant : on évalue expression. Si le résultat est True, on effectue toutes les instructions du bloc
indenté, puis on recommence l’évaluation de expression. Sinon, on passe aux instructions situées après la boucle. Par exemple,
la séquence :

i=0
while i<10:
print(i)
i+=1 #un raccourci pour i=i+1
print("fini !")

affiche à l’écran tous les nombres entre 0 et 9, puis « fini ! ». En effet, lorsque i atteint 9, on l’affiche à l’écran, puis on incrémente
i (qui vaut 10 en bas de la boucle). On réévalue ensuite la condition, mais 10<10 s’évalue en False, donc on sort de la boucle,

Naïm Touil Page 6/20 Math Sup PTSI Saint-Joseph Toulouse


Chapitre 01 Informatique

et on affiche « fini ! » qui est une expression en dehors du corps de la boucle.


Notez bien que l’expression est évaluée uniquement en haut de la boucle : si elle s’évalue en True, on effectue toutes les
instructions du corps de boucle, et on réitère l’évaluation. La boucle suivante affiche les entiers de 1 à 10, puis « fini ! ».

i=0
while i<10:
i+=1 #un raccourci pour i=i+1
print(i)
print("fini !")

Il se peut très bien qu’à la première évaluation de l’expression, celle-ci soit False : dans ce cas on n’effectue jamais le corps
de boucle :

i=-1
while i>=0:
print("on n'affichera jamais ça.")

Enfin, on fera attention avec les boucles while, si on s’y prend mal, on crée un morceau de code qui boucle sans fin :

while True: #l'expression s'évalue en True !


print("ce texte sera affiché, encore et encore !")

L’obtention d’une « boucle infinie » est parfois plus subtile :

x=0.1
while x!=1:
x=x+0.1

On verra dans le chapitre sur la représentation des nombres qu’en arithmétique flottante, additionner 10 fois 0.1 ne fait pas
tout à fait 1 (le résultat est évidemment très proche, mais ne vaut pas exactement 1).

3.4 Boucle inconditionnelle for . . . (pour . . .)

En informatique, on a très souvent besoin qu’une variable prenne successivement comme valeur tous les entiers entre deux
bornes, par exemple de 0 à 100. Évidemment, on peut réaliser ça comme dans la section précédente avec une boucle while :

i=0
while i<=100:
[instructions]
i=i+1

Il est intéressant de raccourcir cette écriture, pour ne pas avoir à initialiser manuellement i ou écrire l’incrémentation i+=1,
limiter les erreurs possibles et rendre le code plus lisible. On utilise alors une boucle inconditionnelle (i prend toutes les valeurs
entières de 0 à 100 sans condition) : la boucle for.
Dans certains langages de programmation, celle-ci ne diffère conceptuellement pas d’une boucle while et est traduite ainsi
au moment de la compilation du programme. Par exemple en C, qui est un langage très populaire :
Une boucle for en langage C Traduction à la compilation

for (i=0; i<=100; i++) { i=0 ;


[instructions] while (i<=100) {
} [instructions]
i++ ;
}

En Python, la structure de la boucle for est légèrement différente, c’est celle-ci :

for element in iterable:


[instructions]

L’itérable est quelque chose que l’on peut itérer : en gros, c’est quelque chose qui fournit une séquence de valeurs. La syntaxe
for element in iterable signifie que la variable element doit prendre successivement toutes les valeurs que fournit l’itérable.
Pour chacune de ces valeurs, on exécute les instructions du corps de boucle. Bien souvent, on utilisera le constructeur range qui

Naïm Touil Page 7/20 Math Sup PTSI Saint-Joseph Toulouse


Chapitre 01 Informatique

fournit des suites (finies) d’entiers. La syntaxe est la suivante, tous les paramètres m, n et p intervenant sont des entiers :

— pour n ≥ 0, range(n) fournit tous les entiers de 0 inclus à n exclu (attention, on s’arrête donc à n − 1)
— on peut décider de commencer à un autre entier que 0 en précisant un autre paramètre : pour m ≤ n, range(m,n) fournit
tous les entiers de m inclus à n exclu.

En précisant un troisième paramètre, on peut faire varier le pas :

— si p > 0, range(m,n,p) fournit successivement les entiers m, m + p, m + 2p, . . . strictement inférieurs à n ;


— si p < 0, range(m,n,p) fournit successivement les entiers m, m + p, m + 2p, . . . strictement supérieurs à n.

Par exemple la boucle :

for i in range(0,m,2):
print(i)

affiche à l’écran successivement tous les entiers pairs entre 0 et m − 1 (la borne m est exclue). La boucle suivante affiche tous
les entiers de n − 1 à 0, (dans l’ordre décroissant) :

for i in range(n-1,-1,-1):
print(i)

Petit conseil : apprendre par coeur la syntaxe range(n-1,-1,-1), elle sert souvent. Donnons un exemple un peu plus complet :
le calcul de 10!

x=1
n=10
for i in range(1,n+1):
x*=i #un raccourci pour x=x*i

On peut vérifier que la variable x contient bien 10! = 3628800 à l’issue de cette boucle.
L’itérable peut également être une liste (dans ce cas element prend successivement toutes les valeurs de la liste), ou une
chaîne de caractères (dans ce cas, element prend successivement comme valeurs tous les caractères de la chaîne), ou encore un
tuple (n-uplet) . . . Ces types seront examinés en section 4.
Donnons un petit exemple, montrant que Python peut faire beaucoup de choses (l’exemple n’est pas à retenir). Le module
itertools permet de faire de la combinatoire. Considérons le triplet (1, 4, 7). On peut facilement produire toutes les permutations
possible du triplet avec la fonction permutations du module itertools :

import itertools # pour utiliser le module (1, 4, 7)


iterable=[Link]((1,4,7)) (1, 7, 4)
for x in iterable: (4, 1, 7)
print(x) (4, 7, 1)
(7, 1, 4)
(7, 4, 1)

3.5 Break et Continue

Ces instructions ne sont pas exigibles, mais sont parfois très pratiques (surtout break). Dans une boucle (while ou for), on
peut utiliser les commandes break et continue : break sort de la boucle, et continue poursuit l’itération en revenant « tout en
haut », sans se préoccuper de ce qu’il y a derrière. Voici un exemple un peu stupide qui mélange les deux :

u=0
while u<100:
print(u)
u+=1 #un raccourci pour u=u+1
if u==5:
break
continue
print(1/0)

Naïm Touil Page 8/20 Math Sup PTSI Saint-Joseph Toulouse


Chapitre 01 Informatique

Ce code ne produit pas d’erreur et n’affiche que 6 entiers : 0, 1, 2, 3, 4 et 5. Dans le corps de boucle, la partie print(1/0)
n’est jamais exécutée (ce qui produirait une erreur) puisqu’elle se trouve après le continue. Lorsque u atteint 5, on rentre dans
le if et on sort de la boucle avec break.
Dans le cas de boucles imbriquées, c’est seulement la boucle interne contenant break ou continue qui est concernée. On
évitera de faire un usage abusif de ces instructions qui peuvent rendre le code difficilement compréhensible, mais on pourra y
recourir avec parcimonie.

3.6 Boucles imbriquées

Il est tout à fait possible d’imbriquer des boucles, ce que l’on fera par la suite pour (entre autres) résoudre un système linéaire
ou trier une liste. Voici un exemple, la recherche de tous les triplets pythagoriciens (triplets (a, b, c) tels que a2 + b2 = c 2 ) où les
trois composantes sont strictement inférieures à 1000. On cherche ici uniquement ceux qui vérifient p 1 ≤ a ≤ b. On va donc utiliser
deux boucles pour balayer tous les entiers 1 ≤ a ≤ b < 1000, et vérifier essentiellement si a2 + b2 est un entier strictement
inférieur à 1000.

N=1000
for a in range(1,N):
for b in range(a,N):
c2=a*a+b*b
if c2>=N**2:
break
elif round(c2**0.5)**2==c2:
print(a,b,round(c2**0.5))

p On a en fait utilisé round qui permet d’arrondir à l’entier le plus proche, et vérifié si le carré de l’entier le plus proche de
a2 + b2 était a2 + b2 lui même. 878 triplets sont affichés à l’écran.

4 Structures de données

4.1 Listes

On étudie ici le type list en Python, qui est essentiel et nous servira souvent. L’appellation list de Python est un peu mal-
heureuse et la traduction en « liste » maladroite : en toute rigueur, il faudrait parler de « tableau redimensionnable inhomogène ».
Mais les sujets de concours parlent de listes, donc nous aussi. Voici un exemple de liste : [True, 4, 5, 3.0].
Comme l’exemple le montre, les listes sont des séquences finies d’éléments, possiblement de types différents. La syntaxe
consiste à les mettre entre crochets, séparés par des virgules.

Construction de listes. On peut construire une liste de plusieurs manières :


— par la donnée explicite des éléments, entre crochets, séparés par des virgules, comme ci-dessus.
— par concaténation de listes (à l’aide de +) : [1, 2, 3]+[4, 5, 6] s’évalue en [1, 2, 3, 4, 5, 6].
— list(iterable) permet de fabriquer une liste à partir d’un itérable. Par exemple, list(range(4)) s’évalue en [0,
1, 2, 3] et list("truc") en [’t’, ’r’, ’u’, ’c’].
— par compréhension, très pratique avec la structure suivante : [f(x) for x in iterable if P(x)], où f(x) est
une expression dépendant (ou non) de x, et P(x) est une expression booléenne (facultative). Par exemple [x*x for
x in range(5) if x % 2==0] s’évalue en la liste [0, 4, 16].
— par slicing (tranchage), qu’on va voir bientôt.
— ...
Accès aux éléments. Pour L une liste, sa longueur (nombre d’éléments, length en anglais) est accessible avec len(L). En notant
n cette longueur, les éléments sont indexés par les entiers de 0 à n − 1. Exemples :

>>> L=list(range(1,6)) #range(1,6) fournit les entiers de 1 à 5.


>>> L[2]
3
>>> L[len(L)-1]
5

Si on demande l’accès à un caractère d’indice négatif i compris entre −1 et −n, où n est la longueur de la liste, celui-ci est
considéré comme étant n + i :

Naïm Touil Page 9/20 Math Sup PTSI Saint-Joseph Toulouse


Chapitre 01 Informatique

>>> L[-1] # très pratique pour accéder au dernier élément !


5
>>> L[-5]
1

L’accès à tout autre indice produit une erreur :

>>> L[len(L)]
Traceback (most recent call last):
File "<console>", line 1, in <module>
IndexError: list index out of range

Retenez bien cette erreur, vous l’aurez souvent !


Modification d’un élément. Étant donnée une liste L, on peut modifier l’élément d’indice i de L en le remplaçant par l’élément
de son choix. La syntaxe est la même que pour une affectation.

>>> L=list(range(1,6))
>>> L
[1, 2, 3, 4, 5]
>>> L[2]=10
>>> L
[1, 2, 10, 4, 5]

Les règles régissant l’indice i sont les mêmes que précédemment.


Slicing (tranchage). On peut créer une nouvelle liste en extrayant certains éléments d’une liste. Pour extraire les éléments d’in-
dice entre d inclus et f ≥ d exclu, on utilise L[d:f] : la liste obtenue est donc composée des éléments L[d], L[d+1],...,
L[f-1]. L’un ou l’autre de ces deux indices peut être omis, et même les deux (dans ce cas, d vaut 0 et f vaut la longueur
de la liste). Ce mécanisme est tolérant envers les indices trop grands ou trop petits (attention, les indices négatifs entre −1
et −n sont interprétés comme précédemment), et si d ≥ f , on obtient la liste vide.

>>> L
[1, 2, 10, 4, 5]
>>> L[3:4]
[4]
>>> L[4:3]
[]
>>> L[:4]
[1, 2, 10, 4]
>>> L[:8]
[1, 2, 10, 4, 5]

On peut également spécifier un pas, positif ou négatif. L’interprétation est la même que pour les listes et l’itérateur range,
on ne précisera donc pas ici.

>>> L[::2]
[1, 10, 5]

Méthodes sur les listes. Python est un langage orienté objet. À chaque classe d’objets (comme les listes) peuvent s’appliquer
plusieurs méthodes, qui modifient l’objet ou renvoient certaines de ces caractéristiques. Au programme en classes prépa-
ratoires, on trouve seulement append et pop, qui permettent d’ajouter ou d’enlever un élément en fin de liste. La syntaxe
générale de l’utilisation d’une méthode sur un objet est la suivante : [Link](parametres).
Le tableau suivant récapitule les principales méthodes sur les listes. Le but est de présenter ce qu’on peut faire en Python,
et de voir que ces opérations ne sont pas toutes triviales pour le processeur. La colonne complexité ne peut être comprise
qu’après le chapitre dédié. On note n la longueur de la liste L.

Naïm Touil Page 10/20 Math Sup PTSI Saint-Joseph Toulouse


Chapitre 01 Informatique

méthode description complexité


[Link](x) Ajoute x à la fin de L. O (1) (amorti)
[Link](T) Ajoute les éléments de T à la fin de L (équivalent à L+=T). O (len(T)) (amorti)
[Link](i,x) Ajoute l’élément x en position i de L, en décalant les suivants vers la droite. O (n − i) (amorti)
[Link](x) Supprime de la liste la première occurrence de x si x est présent, sinon O (n)
produit une erreur.
[Link]() Supprime le dernier élément de L, et le renvoie. O (1)
[Link](i) Supprime l’élément d’indice i de L, en décalant les suivants vers la gauche. O (n − i)
Cette méthode renvoie l’élément supprimé.
[Link](x) Retourne l’indice de la première occurrence de x dans L si x est présent, O (n)
produit une erreur sinon.
[Link](x) Retourne le nombre d’occurrences de x dans L. O (n)
[Link]() Trie la liste L dans l’ordre croissant (en place). O (n log (n))
[Link]() Renverse la liste (en place). O (n)
Attention, ces méthodes ne renvoient en général rien : elles modifient l’objet. C’est le cas pour append, qui permet d’ajouter
en fin de liste un nouvel élément. Pour ajouter x à la fin de L, on écrit simplement [Link](x), et non pas L=[Link](x).
En effet, [Link](x) est une expression dont l’évaluation produit None, c’est-à-dire rien. Écrire L=[Link](x) revien-
drait à affecter None à la variable L, ce qui n’est pas a priori ce qu’on veut faire ! Voir la section 5 pour des précisions sur
None.
Listes et références. Ce point est important. Vous ferez l’erreur un jour, mais vous vous douterez du problème si vous avez bien
compris ce paragraphe. Prenons tout de suite un exemple :

>>> T=[0,2,3]
>>> U=T
>>> T[0]=1
>>> [Link](4)
>>> print(U)
[1, 2, 3, 4]

Si on modifie T, on modifie U. Le comportement semble bien différent des variables ! Essayons autre chose :

>>> T=[0,2,3]
>>> U=T[:]
>>> T[0]=1
>>> [Link](4)
>>> print(U)
[0, 2, 3]

Le comportement est plus sympathique. Il faut savoir que lorsqu’on crée une liste, la variable utilisée est ce qu’on appelle
une référence (ou un pointeur) vers l’emplacement mémoire où est stockée la liste. L’instruction U=T du premier exemple
stocke dans la variable U la référence stockée dans T. Autrement dit, l’emplacement mémoire désigné par T et U est le même !
Lorsqu’on effectue l’instruction T[0]=1, on va modifier directement la mémoire (de même avec append), et il est logique
que ce changement soit visible lorsqu’on tape print(U), puisque cette action va chercher en mémoire ce qu’indique U.
Dans le deuxième exemple, l’instruction U=T[:] est différente : on crée une liste dont les éléments sont les mêmes que
ceux de T, mais ailleurs en mémoire. Autrement dit, les références T et U pointent vers des endroits différents en mémoire,
et donc si on modifie l’une, l’autre n’est pas modifiée.
Liste de listes. On utilisera couramment des listes qui contiennent des listes, en particulier pour représenter des matrices. L’accès
aux éléments se fait de manière similaire :

>>> L=[[0,1,2,3],[4,5]] # une liste de deux listes


>>> L[0] # premier élément de L
[0, 1, 2, 3]
>>> L[1][0] # premier élément du deuxième élément de L
4
>>> L[0][2]=6
>>> print(L)
[[0, 1, 6, 3], [4, 5]]

Naïm Touil Page 11/20 Math Sup PTSI Saint-Joseph Toulouse


Chapitre 01 Informatique

Pour terminer, faisons une mise en garde supplémentaire, concernant encore les références :

>>> T=[[0,2],[3,4]]
>>> U=T[:]
>>> U[0][0]=1
>>> print(T)
[[1, 2], [3, 4]]

Ici, on a pris soin de recopier les éléments de T. Mais comme ces éléments sont des références vers [0,2] et [3,4], le
problème reste le même que précédemment puisque ces listes-là n’ont pas été recopiées. Il aurait fallu écrire :

U=[A[:] for A in T]

Mais si T avait été une liste de listes de listes, le problème se serait encore posé. Faisons deux remarques :
— premièrement, on manipulera rarement des listes de listes de listes ;
— deuxièmement, il existe un module copy dont la fonction deepcopy permet de copier « en profondeur » un objet.

4.2 Tuples
Présentation. Un tuple ressemble beaucoup à une liste, mais on ne peut ni modifier ses éléments, ni lui en ajouter ou en enlever.
La structure mathématique associée est celle de n-uplet. On parle de structure immuable (ou statique, ou encore non
mutable). En contrepartie de cette rigidité, les tuples sont très compacts (ils occupent peu de mémoire) et l’accès à leurs
éléments est rapide.
Pour la syntaxe, on crée un tuple en écrivant ses éléments, séparés par des virgules et encadrés par des parenthèses. S’il n’y
a pas d’ambiguïté, les parenthèses peuvent être omises (en pratique, dès que le nombre d’éléments du tuple est au moins
2). Un tuple constitué d’un seul élément a doit être écrit a, ou (a,). Le tuple sans élément se note ().
Opérations sur les tuples. Faisons une brève session Python de démonstration, pour vérifier que les opérations sur les listes
sont valables pour les tuples :

>>> t=4, True, 0.5 ; v=(6,) ; w=((7,8),) # w est un tuple dont le seul élément est un tuple
>>> t+v
(4, True, 0.5, 6)
>>> t[1:]
(True, 0.5)
>>> t+w
(4, True, 0.5, (7, 8))
>>> len(t+w)
4

Comme on le voit, un élément d’un tuple peut être un tuple à son tour. Attention, les tuples sont immuables : on ne peut
modifier un élément. L’erreur ci-dessous est très explicite.

>>> t[0]=3
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment

Déconstruction d’un tuple. On peut déconstruire un tuple par affectation simultanée à un tuple de variables de la même taille,
pour réaliser une affectation simultanée :

>>> couple=(1,2)
>>> (x,y)=couple
>>> print(x) ; print(y)
1
2

Notez que les parenthèses autour du tuple de variables sont facultatives et qu’on pourrait (ce qu’on fait en pratique) écrire
x,y=couple. Si le tuple de variables n’est pas de la même taille que le tuple à déconstruire, on obtient une erreur :

Naïm Touil Page 12/20 Math Sup PTSI Saint-Joseph Toulouse


Chapitre 01 Informatique

>>> a,b,c=couple
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: need more than 2 values to unpack
>>> triplet=1,2,3
>>> x,y=triplet
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: too many values to unpack (expected 2)

L’erreur indique à chaque fois que le tuple à droite n’est pas de la bonne taille, vis-à-vis du tuple de variables. On peut main-
tenant expliquer un comportement spécifique à Python mais fort pratique pour échanger les contenus de deux variables :

a,b=b,a

De même que précédemment, on construit d’abord le tuple qui contient les valeurs de b et a qu’on déconstruit ensuite pour
affecter le contenu aux variables a et b.

4.3 Chaînes de caractères

Une donnée de type chaîne de caractères est une suite de caractères quelconques. Une chaîne de caractères s’indique en
écrivant les caractères en question soit entre apostrophes, soit entre guillemets : ’Bonjour’ et "Bonjour" sont deux écritures
correctes de la même chaîne. Du point de vue structurel, les chaînes sont très proches des tuples. Comme eux, elles sont im-
muables : on ne peut pas changer un caractère.

Concaténation, accès à des caractères, slicing. Comme pour les tuples, on peut concaténer deux chaînes de caractères à l’aide
de + pour en produire une troisième, la longueur de la chaîne est donnée par len, et l’accès aux caractères est similaire.

>>> "C'est une"+" phrase complète."


"C'est une phrase complète."
>>> a="Une chaîne de caractères"
>>> a[0] ; a[5] ; a[-1]
'U'
'h'
's'
>>> a[::2]
'Uecan ecrcèe'

Attention, les chaînes de caractères sont immuables : une fois créées, on ne peut pas les modifier, ou leur rajouter des
éléments. Il faut créer une nouvelle chaîne qu’on peut éventuellement réaffecter à la même variable.

>>> a='rateau'
>>> a[0]='b'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'str' object does not support item assignment
>>> a='b'+a[1:]
>>> a
'bateau'

La table des caractères ASCII. Les 128 caractères de la table ASCII standard comprennent les lettres minuscules et majuscules
non accentuées, les chiffres de 0 à 9, à peu près tous les caractères d’un clavier QWERTY (pas de lettres accentuées !), et des
caractères d’espacement. À chaque caractère est associé un code entre 0 et 127 (donc représentable sur 7 bits). En Python,
les fonctions ord et chr permettent de passer d’un caractère à son numéro et réciproquement.

>>> ord('a') >>> chr(48+9)


97 '9'
>>> chr(97+25) >>> ord('A')
'z' 65
>>> ord('0') >>> chr(65+25)
48 'Z'

Naïm Touil Page 13/20 Math Sup PTSI Saint-Joseph Toulouse


Chapitre 01 Informatique

On notera que les lettres minuscules (respectivement les lettres majuscules, les chiffres) sont codés par des numéros conti-
gus, avec ’a’ (respectivement ’A’, ’0’) ayant le plus petit numéro. Aujourd’hui, l’ASCII a été remplacé par UNICODE,
qui l’inclut. Les fonctions ord et chr fonctionnent en fait avec d’autres caractères, non ASCII.

>>> ord('à')
224
>>> chr(201)
'É'

Quelques méthodes sur les chaînes de caractères. Comme les listes, les chaînes de caractères possèdent leurs propres mé-
thodes, qui ne sont pas exigibles mais peuvent faire l’objet de questions aux concours si la documentation est rappelée. On
en donne quelques-unes ici, les deux premières seront celles qui nous serviront le plus. Comme les chaînes de caractères
sont immuables, les méthodes ne modifient jamais la chaîne mais renvoie un nouvel objet.
méthode description
[Link](c) sépare la chaîne s autour du caractère c. Le résultat est une liste de chaînes de ca-
ractères. Par exemple "une petite chaine".split(" ") donne ["une", "petite",
"chaine"].
[Link](L) l’inverse de l’opération précédente. Par exemple "-".join(["a", "bc"]) donne
"a-bc".
[Link](c) compte le nombre d’occurrences du caractère c dans s.
[Link](c) indique la première position du caractère c dans s, ou -1 s’il n’y est pas.
[Link](n) rajoute à la fin de s autant d’espaces que nécessaire pour atteindre n caractères. Avec
[Link](n,c), on remplit avec le caractère c. De même avec ljust pour remplir au
début (right/left).
[Link](s1,s2) remplace toutes les apparitions de la chaîne s1 dans s par la chaîne s2.
Caractères particuliers. Si la chaîne doit contenir un des caractères ’ ou " cela fournit un critère pour choisir l’une ou l’autre
manière de l’écrire : ’"Oui", dit-il’ ou "C’est exact". Une autre manière d’éviter les problèmes avec le caractère
d’encadrement consiste à l’inhiber par l’emploi de \, comme dans la chaîne ’Il ajouta: "c\’est exact !"’.
L’encadrement par de triples guillemets ou de triples apostrophes permet d’indiquer des chaînes qui s’étendent sur plusieurs
lignes, et peut servir à ne pas trop réfléchir si la chaîne doit contenir les caractères ’ ou ".

a="""Cette chaîne s'étend


sur

plusieurs lignes. C'est "beau"."""

L’affichage basique d’une telle chaîne montre bien que les fins de ligne, représentées par le signe \n, ont été conservées.
L’affichage à l’aide de la fonction print fournit le résultat attendu :

>>> a
'Cette chaîne s'étend\n sur\n \n plusieurs lignes. C'est "beau".'
>>> print(a)
Cette chaîne s'étend
sur
plusieurs lignes. C'est "beau".

Notez aussi que \t sert à encoder les tabulations. Le backslash étant lui-même un caractère spécial, on le fera précéder
d’un autre backslash s’il doit figurer dans la chaîne. Par exemple :

>>> s="\\t est une tabulation, \\n est un saut de ligne"


>>> print(s)
\t est une tabulation, \n est un saut de ligne

Chaînes de caractères comme commentaires. Pour commenter son code, on peut utiliser le caractère dièse # : tout ce qui suit
sur la même ligne est ignoré. Lorsqu’on envoie une suite d’instructions de l’éditeur vers la console, une chaîne de caractères
sera perçue comme telle, mais seule elle n’a aucune incidence sur le reste du programme, tout comme une expression
quelconque comme 10 ou 2+3. On peut donc utiliser les triples quotes pour commenter facilement un morceau de code
s’étendant sur plusieurs lignes.
Conversion. "42" est une chaîne de caractères, pas un entier. Ainsi "42"+5 n’a aucun sens. Par contre, "42" * 5 vaut "4242424242".
int, float, str, . . . permettent de convertir un type en un autre.

Naïm Touil Page 14/20 Math Sup PTSI Saint-Joseph Toulouse


Chapitre 01 Informatique

4.4 Dictionnaires

Un dictionnaire est un objet permettant de stocker des couples (clé, valeur), chaque clé ne pouvant être présente que dans un
seul couple. Un dictionnaire au sens usuel en est un exemple, où les clés sont les mots de la langue et les valeurs les définitions de
ces mots. Un autre exemple serait celui d’un annuaire : à partir d’un couple (nom, prénom) d’une personne (la clé), on souhaite
retrouver son numéro de téléphone (la valeur).

Syntaxe. Un dictionnaire s’écrit entre accolades, les couples (clé, valeur) indiqués sous la forme clé:valeur, séparés par des
virgules. Par exemple :

>>> D={'a': 4, 0:5, (1,2):"coucou"}

Comme on le voit, il n’y a aucune contrainte d’homogénéité sur les clés ou les valeurs.
Opérations sur un dictionnaire. Le plus souvent, on partira d’un dictionnaire vide pour lui rajouter les éléments un à un. Un
dictionnaire vide s’obtient via dict() ou simplement {} :

>>> dict(), {}
({}, {})

L’accès à un élément e à partir de sa clé k dans un dictionnaire D se fait via D[k], par exemple avec le dictionnaire précédent :

>>> D['a'], D[(1,2)]


(4, 'coucou')

Si la clé k n’est pas présente, l’opération D[k] produit une erreur.

>>> D['b']
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: 'b'

Tester si une clé k est présente se fait via k in D (ou k in [Link]()) :

>>> 'b' in D, 'a' in D


(False, True)

L’ajout d’un nouveau couple (k,e) ou la modification de l’élément e associé à une clé k se fait de la même manière que
l’accès, via D[k]=e.

>>> D['b']=5 ; D[(1,2)]="coucoubis"


>>> D
{'a': 4, 0: 5, (1, 2): 'coucoubis', 'b': 5}

Une mise en garde : on ne peut pas utiliser un objet mutable (comme une liste, ou un dictionnaire, par exemple) comme clé
d’un dictionnaire. Il faut se restreindre à des objets immuables (comme les entiers, les flottants, les chaînes de caractères,
les tuples de tels éléments, etc . . .)
Quelques méthodes et fonctions sur les dictionnaires. Voici quelques méthodes, sans exhaustivité, permises sur les diction-
naires. Dans la suite, D désigne un dictionnaire.
méthode description
len(D) renvoie le nombre de couples (clé, élément) stockés dans D.
[Link](k) supprime le couple de clé k du dictionnaire, si un tel couple est présent.
[Link]() renvoie les clés présentes dans le dictionnaire. L’objet renvoyé est un itérable, on peut
donc utiliser une syntaxe du type for k in [Link](): ... Écrire simplement for k
in D est équivalent.
[Link]() renvoie une copie du dictionnaire.
Un mot sur la complexité. Le programme officiel impose d’utiliser en première année les dictionnaires comme des boîtes noires,
sans indication sur la manière dont ils sont implémentés. On pourra considérer que toutes les opérations (création, ajout ou
modification, suppression) se font en temps constant. Le lecteur voulant aller plus loin pourra consulter l’article Wikipédia
sur les tables de hachage, qui est la méthode la plus répandue pour implémenter un dictionnaire, et notamment en Python,
ou encore consulter le chapitre dédié du polycopié.

Naïm Touil Page 15/20 Math Sup PTSI Saint-Joseph Toulouse


Chapitre 01 Informatique

5 Fonctions

Les fonctions sont d’une importance capitale en informatique, et plus prosaïquement quasiment toutes les questions des sujets
de concours demandent d’écrire ou d’examiner des fonctions.

5.1 Motivation
n
X n
X n
X
Imaginons que l’on veuille calculer 2k , 3k , . . . C’est-à-dire des sommes de la forme x k pour plusieurs x et n. On
k=0 k=0 k=0
n
X
veut donc calculer plusieurs valeurs de la fonction de plusieurs variables (x, n) 7→ x k.
k=0

L’idéal serait de définir cette fonction, ce qu’on peut faire :

def f(x,n): >>> f(2, 5)


s=0 63
for k in range(n+1): >>> f(3, 4)
s+=x**k 121
return s

5.2 Notions et syntaxe de base

Une fonction en informatique est une séquence d’instructions, dépendant de paramètres d’entrée (appelés arguments), et
retournant un résultat.
Deux points de vue, souvent complémentaires, permettent de préciser ce qu’est une fonction :

— c’est une séquence d’instructions qui permet de réaliser un calcul précis, que l’on peut utiliser plusieurs fois.
— c’est une brique de base d’un problème plus complexe.

La structure générale d’une déclaration de fonction en Python se fait avec le mot-clef def de la façon suivante :

def nom_fonction(a_1,a_2,...,a_k): # nom_fonction: nom de la fonction, a_1,..,a_k : arguments


""" Description de l'action de la fonction """ # spécification de la fonction
instruction 1
instruction 2
...
instruction p
# ici, on est hors de la définition de la fonction.

— La première ligne def nom_fonction(a_1,...,a_k) est l’en-tête de la fonction. Les éléments a_1,...,a_k sont des
identificateurs appelés arguments formels de la fonction et nom_fonction est le nom de la fonction.
Pour une fonction ne prenant pas d’arguments, on écrit simplement def fonction():, les parenthèses étant indispen-
sables. Le nom de la fonction est un identificateur qui suit les mêmes règles que les identificateurs de variables (d’ailleurs
la définition d’une fonction n’est rien d’autre qu’une affectation : celle d’un objet de type function à une variable).
— La seconde (qui est facultative et peut être sur plusieurs lignes) est une chaîne de caractères appelée chaîne de documen-
tation décrivant la fonction : ce que doivent respecter les paramètres passés en entrée, l’action effectuée et la nature du
résultat retourné.
— La suite d’instructions est le corps de la fonction.
— Le retour à une indentation au même niveau que def marque la fin de la fonction, tout ce qui est à ce niveau ne fait plus
partie de la fonction.

Attention, le rôle d’une définition de fonction n’est pas d’exécuter les instructions qui en composent le corps, mais uniquement
de mémoriser ces instructions en vue d’une exécution ultérieure (facultative !), provoquée par une expression faisant appel à la
fonction. Par exemple, définir la fonction qui suit ne provoque pas d’erreur.

def fonction_erreur():
print(1/0)

Évidemment, l’appeler en provoque une !

Naïm Touil Page 16/20 Math Sup PTSI Saint-Joseph Toulouse


Chapitre 01 Informatique

Appel d’une fonction. L’appel de la fonction nom_fonction présentée ci-dessus se fait par :

nom_fonction(e_1,e_2,...,e_k),

où e_1,...,e_k sont des expressions. Elles forment les arguments effectifs de l’appel à la fonction : lors de l’appel e_1
(respectivement e_2,...,e_k) est évaluée, puis le résultat est affecté à a_1 (respectivement a_2,...,a_k) juste avant
l’exécution du corps de la fonction. Tout se passe comme si l’exécution de la fonction commençait par la suite d’instructions
d’affectation
et se poursuivait avec
a_1=e_1 instruction 1
a_2=e_2 instruction 2
... ...
a_k=e_k instruction p

L’instruction return. Le corps de la fonction comprend bien souvent une ou plusieurs instructions de la forme return resultat,
où resultat est une expression. Lors du déroulement du corps de la fonction, si une telle instruction est rencontrée, alors
l’expression resultat est évaluée, l’exécution de la fonction est interrompue et la valeur de resultat prend la place de
nom_fonction(e_1,e_2,...,e_k) là où la fonction a été appelée. Prenons un exemple simple :

def incremente(x):
return x+1

Si on exécute a=incremente(6-2)+9, alors :


— 6-2 s’évalue en 4.
— x prend la valeur 4 dans la fonction.
— x+1 s’évalue en 5, qui est retourné par la fonction.
— incremente(6-2) est donc remplacée par 5.
— incremente(6-2)+9 s’évalue donc en 14, qui est ensuite affecté à la variable a.
Le type « rien ». Si la fonction ne comprend pas de return ou qu’aucun return n’est rencontré lors de l’exécution, la fonction ne
renvoie rien. On dit parfois qu’elle fonctionne uniquement par effets de bord, et c’est là une différence fondamentale avec
les fonctions en mathématiques. Il y a un type pour ça : NoneType, qui comporte une unique valeur : None. La fonction
suivante ne prend aucun paramètre en entrée, se contente d’afficher 4 à l’écran, et ne renvoie rien : elle agit par effets de
bord.

def affiche4():
print(4)

Lors de l’évaluation de a=affiche4(), 4 est affiché à l’écran, on sort de la fonction (car on est arrivé en bas !) et a prend la
valeur None. Notez que return seul (sans rien derrière) est souvent fort utile pour interrompre une fonction. La fonction
en question renvoie alors None.
Différence entre print et return. Une erreur classique est de confondre print et return. return est une instruction de sortie
de fonction, print est une fonction Python, qui affiche l’argument passé en entrée à l’écran et qui ne renvoie rien. Lorsqu’on
teste une fonction dans la console, on ne voit pas vraiment la différence mais elle est pourtant significative : une fonction
sans return ne renvoie rien !
Prenons l’exemple de la fonction suivante, qui calcule un PGCD.

def PGCD(a,b):
"""Avec a et b>0, renvoie le PGCD de a et b."""
while b!=0:
a,b=b,a%b
return a

Exécuté dans la console, on ne verrait pas de grande différence entre cette fonction et la même avec print à la place de
return. Si maintenant, on veut utiliser cette fonction pour calculer un PPCM, on définit alors la fonction suivante :

def PPCM(a,b):
"""Avec b>0, renvoie le PPCM de a et b."""
return a*b//PGCD(a,b)

L’appel PPCM(6,4) produit bien 12. Avec print(a) au lieu de return a dans la fonction PGCD, l’expression PGCD(6,4)
est remplacée par None, et l’évaluation a*b//PGCD(a,b) produit une erreur :

Naïm Touil Page 17/20 Math Sup PTSI Saint-Joseph Toulouse


Chapitre 01 Informatique

>>> PPCM(6,4)
2
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in PPCM
TypeError: unsupported operand type(s) for //: 'int' and 'NoneType'

Remarquez que l’erreur est très explicite : l’opérateur // ne peut faire d’opération entre un entier (de type int, obtenu
ici par l’évaluation de 6*4) et un objet de type NoneType, c’est-à-dire None. Vous vous posez peut-être la question : mais
qu’est-ce que le 2 qui traîne ? Il provient de notre fonction PGCD, qui a été appelée par PPCM, s’est déroulée sans accroc, et
a bravement affiché à l’écran le PGCD de a et b, comme demandé puisqu’on a utilisé print.
Chaîne de documentation. Il est important de préciser ce que fait une fonction lorsqu’on l’écrit. La chaîne de documentation
ainsi que l’en-tête, sont accessibles lorsqu’on tape help(nom_fonction) :

>>> help(PPCM)
Help on function PPCM in module __main__:
PPCM(a, b)
Avec b>0, renvoie le PPCM de a et b.

Et cela marche aussi avec les fonctions Python.

>>> from math import *


>>> help(log2)
Help on built-in function log2 in module math:

log2(...)
log2(x)

Return the base 2 logarithm of x.

Il existe certaines règles qui régissent la rédaction des chaînes de documentation, mais il est inutile de s’embêter avec ça.
Mettez une chaîne de caractères après l’en-tête qui explique un peu ce que fait votre fonction et ce sera déjà très bien. Cette
chaîne est bien sûr facultative.

5.3 Variables locales et globales

Dans les fonctions PGCD et PPCM de la sous-section précédente, les variables a et b ont été utilisées à peu près partout : comme
paramètres d’appel des deux fonctions mais également comme variables pour calculer le PGCD puisque par exemple la valeur
de retour de PGCD est a. Pourtant, Python ne se mélange pas les pinceaux et produit le résultat auquel on s’attend, parce que a
et b dans les fonctions sont des variables locales. Si elle n’est pas explicitement déclarée globale, toute variable apparaissant
dans une fonction comme membre gauche d’une affectation est locale à cette fonction. Cela signifie que sa portée est réduite à
la fonction, qu’elle est créée à chaque fois que la fonction est appelée et « détruite » à la fin de chaque exécution. Par exemple,
supposons que la variable a n’ait pas été affectée mais la fonction PGCD précédente déclarée :

>>> PGCD(8,3)
1
>>> a
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'a' is not defined

On voit bien que a est inconnu en dehors de la fonction PGCD. Les paramètres des fonctions se comportent comme des variables
locales : on peut les modifier mais cette modification est interne à la fonction.

>>> a=5 ; b=7


>>> p=PGCD(a,b)
>>> print(a)
5

On parle de passage par valeurs : lors de l’appel à PGCD, les valeurs de a et b sont recopiées et les variables a et b de la
fonction ne sont pas les mêmes que les variables a et b qu’on a définies en dehors de la fonction.
A l’opposé de cela, les variables globales sont des variables créées à l’extérieur de toute fonction. Elles existent depuis le

Naïm Touil Page 18/20 Math Sup PTSI Saint-Joseph Toulouse


Chapitre 01 Informatique

moment de leur création, jusqu’à la fin de l’exécution du programme. Une variable globale peut être utilisée à l’intérieur d’une
fonction si elle n’est pas le membre gauche d’une affectation ou le nom d’un paramètre. Par exemple, la fonction suivante ajoute
le contenu de la variable (nécessairement globale !) n au paramètre x et renvoie le résultat de l’addition.

def ajoute_n(x):
return x+n

Si n n’est pas défini au moment de l’appel à ajoute_n, on obtient bien sûr une erreur. En général, on réserve l’usage des
variables globales aux constantes d’un problème. Si on veut réaliser une simulation en cinétique des gaz, on pourra commencer le
script de simulation par R=8,3144621 (la constante universelle des gaz parfaits), et on pourra librement utiliser R dans n’importe
quelle fonction.
Pour pouvoir affecter à une variable globale dans une fonction, cette variable doit faire l’objet d’une déclaration explicite
comme variable globale de la forme global variable_globale. Par exemple, imaginons que l’on veuille maintenir un compteur,
qui contient le nombre de fois où une certaine fonction a été appelée. On peut donc utiliser une variable globale nombre_appels,
qu’on incrémentera de 1 dans l’appel de la fonction. La fonction en question commencerait donc par :

global nombre_appels
nombre_appels+=1

Ainsi, une variable est locale sauf si :

— elle est explicitement déclarée globale ;


— ou bien elle est utilisée sans être affectée.

En général, on n’utilisera pas de variables globales, sauf si la situation le justifie. À l’opposé des fonctions qui fonctionnent
par effets de bord, il y a les fonctions pures : elles n’agissent pas sur l’environnement (même par affichage !) et n’en dépendent
pas (elles n’ont pas recours à des variables globales). Par exemple, les fonctions PGCD et PPCM définies plus haut sont pures.

5.4 Références vers des objets mutables

Le point abordé maintenant est un peu subtil, mais n’est finalement pas très dur à comprendre. Considérons la fonction
suivante :

def ajoute_zero(T):
[Link](0)

et regardons l’effet de la fonction sur une liste quelconque :

>>> L=[3,4,7]
>>> ajoute_zero(L)
>>> print(L)
[3, 4, 7, 0]

On remarque que la fonction a eu un effet global sur la liste L (un effet de bord !). Lorsqu’on déclare une liste (ici L), l’identi-
ficateur est en fait une référence (on parle aussi de pointeur) vers l’emplacement mémoire occupé par la liste.
Lorsqu’on passe une liste en paramètre d’une fonction, c’est la référence qui est utilisée (en particulier, les éléments de la liste
ne sont pas recopiés ailleurs). La méthode append modifie ce qu’il y a en mémoire, et c’est pour cette raison que l’effet est visible
en dehors de la fonction. Le comportement est sensiblement différent si l’on définit ajoute_zero comme ceci :

def ajoute_zero(T):
T=T+[0]

Si on exécute la même suite d’instructions que précédemment, on obtient :

>>> L=[3,4,7]
>>> ajoute_zero(L)
>>> L
[3, 4, 7]

Ici, on commence par créer la liste T+[0] en recopiant ailleurs en mémoire les éléments de T et en y ajoutant 0. Après
l’affectation T=, la référence T pointe maintenant vers cette nouvelle liste. Cette nouvelle référence est locale à la fonction : la
liste [3,4,7,0] n’existe que dans la fonction et est donc « détruite » en fin de fonction.

Naïm Touil Page 19/20 Math Sup PTSI Saint-Joseph Toulouse


Chapitre 01 Informatique

Remarquez qu’avec T+=[0], on obtient le même comportement qu’avec append. C’est parce que sur les listes, += est similaire
à la méthode extend qui s’utilise comme suit : [Link](T2) rajoute à la fin de la liste T le contenu de la liste T2, la référence
à T n’étant pas modifiée (voir les méthodes sur les listes).

5.5 Une fonction : un objet comme les autres


Fonctions en paramètres d’autres fonctions. On n’a pas encore parlé du type associé à une fonction. Sans surprise, il s’agit
du type function. Remarquez que lorsqu’on demande à Python d’afficher une fonction, il renvoie une suite de caractères
bizarres :

>>> type(PPCM)
<class 'function'>
>>> print(PPCM)
<function PPCM at 0x7fd55b535268>

En fait, 0x7fd55b535268 est l’emplacement mémoire occupé par la fonction : il faut bien la stocker quelque part ! Le préfixe
0x indique que l’emplacement mémoire est codé en hexadécimal.
Les fonctions sont des objets comme les autres en Python. En particulier, il est possible de les passer comme paramètres
Xn
d’autres fonctions. Généralisons un peu l’exemple vu précédemment : on peut écrire une fonction qui calcule g (x)k
k=0
pour tous paramètres x, n et g :

def f(x,n,g): >>> f(5, 5, cos)


s=0 0.984965422678516
for k in range(n+1): >>> f(3, 4, lambda x: x)
s+=g(x**k) 121
return s

Dans ces exemples, cos est la fonction cosinus classique, qui se trouve dans le module math. Remarquez que lambda permet
de définir une fonction sans lui donner un nom : la syntaxe est lambda variable: expression. On a ici défini la fonction
identité, et on retrouve le même résultat qu’avec la version précédente de la fonction f .
Fonctions locales à d’autres fonctions. De la même façon que les variables définies dans une fonction sont locales, on peut
définir une fonction locale à une autre. Une variante (un peu stupide) de la fonction précédente est-celle ci :

def f(x,n,g):
def terme(k):
return g(x**k)
s=0
for k in range(n+1):
s+=terme(k)
return s

Ici, la fonction terme est locale à la fonction f : elle n’est pas définie en dehors de la fonction f. Remarquez que x est utilisé
comme « variable globale » de la fonction terme : c’est normal et tout à fait légitime. Python va chercher en dehors de la
fonction ce qu’il ne connaît pas. Même si x est également une variable définie en dehors de la fonction, on considère le
« plus petit contexte définissant x » : ici celui de la fonction f.
Arguments optionnels. Dans la définition d’une fonction, on peut déclarer certains arguments comme optionnels en leur don-
nant une valeur par défaut, utiles s’ils ne sont pas précisés lors de l’appel de la fonction. C’est une possibilité qu’on n’utilisera
pas pour nos propres fonctions, mais utile pour comprendre beaucoup de fonctions internes à Python.
Prenons un exemple minimaliste, avec l’argument optionnel y.

def f(x,y=1): >>> f(0)


return x+y 1
>>> f(0,y=4)
4

Naïm Touil Page 20/20 Math Sup PTSI Saint-Joseph Toulouse

Vous aimerez peut-être aussi