0% ont trouvé ce document utile (0 vote)
4 vues28 pages

Introduction aux Fonctions en Python

Transféré par

lamialililala
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)
4 vues28 pages

Introduction aux Fonctions en Python

Transféré par

lamialililala
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

Note de cours AP1 - Séquence 2 : Approfondissement

Fonctions

Rappels

En programmation, une fonction est

un morceau de programme
portant en général un nom
acceptant zéro, un ou plusieurs paramètres
produisant le plus souvent un résultat.

Des exceptions existent, mais la forme la plus courante d'une fonction est donc proche de celle d'une fonction mathématique.

L'utilisation de fonctions améliore les aspects suivants du code :

Lisibilité :
isoler une partie du programme (par exemple un gros calcul compliqué)
éviter une trop grande imbrication des if, des while
Modularité et robustesse:
réutiliser le même code plusieurs fois (évite de recopier le code)
faciliter la correction des bugs, l'évolution et la maintenance
Généricité :
changer la valeur des paramètres (même calcul mais avec différentes valeurs de départ)

Fonctions prédéfinies et bibliothèque standard

En Python, il existe un grand nombre de fonctions prédéfinies, que nous avons déjà utilisées, par exemple :

int(obj) : 1 paramètre, 1 résultat. Reçoit en paramètre un objet (par exemple str ou float), essaie de le transformer en entier et renvoie l'entier
obtenu.

In [1]:
int("34")

Out [1]: 34

len(obj) : 1 paramètre, 1 résultat. Reçoit un objet (par exemple str) et renvoie sa longueur.

In [2]: len("bonjour")

Out [2]: 7

randint(mini, maxi) : 2 paramètres, 1 résultat. Reçoit deux nombres, et renvoie un entier aléatoire compris entre ces deux nombres (inclus).

In [3]:
from random import randint
randint(1, 34)

Out [3]: 8

Il y en a beaucoup d'autres, comme print, input, float, str....

Ces fonctions sont appelées prédéfinies (ou built-in)

il est inutile de les connaître toutes par coeur


liste des fonctions prédéfinies sur cette page

Il existe également de nombreux modules officiels (par exemple le module random)

bibliothèques de fonctions, de types et d'objets


liste des modules prédéfinis documentée ici.

Définition de fonction

Pour définir une nouvelle fonction on utilise la syntaxe suivante :

# ligne suivante : en-tête de fonction


def nom_fonction(param_1, ..., param_n):
# corps de la fonction
# utilisant param_1 à param_n
...
# peut renvoyer un résultat :
return resultat

Une fonction peut :

prendre un certain nombre de paramètres (ici, n, qui s'appellent param_1 à param_n)


renvoyer une valeur (via l’instruction return)

Appel de fonction
Une fois définie, nom_fonction peut être utilisée dans le code (on parle d'un appel) en indiquant entre parenthèses ses paramètres séparés par des
virgules :

# définition de fonction
def nom_fonction(param_1, ..., param_n):
...

# reste du programme
...
# appel de la fonction :
une_var = nom_fonction(expr_1, ..., expr_n)

Exemples

Fonction à paramètres et résultat

In [4]:
# fonction à deux paramètres produisant un résultat
def maximum(a, b):
if a >= b:
return a
else:
return b

In [5]: nb1 = 14
nb2 = 31

maximum(nb1, nb2) # ne sert à rien !!

# On appelle la fonction et on garde le résultat dans c :


c = maximum(nb1, nb2)
print("le max de", nb1, "et", nb2, "est", c)

# On peut aussi utiliser directement le résultat :


print("le max de", nb1, "et", nb2, "est", maximum(nb1, nb2))

le max de 14 et 31 est 31
le max de 14 et 31 est 31

Entraînement :

Décrire l'exécution pas à pas du programme (avec état de la mémoire). On peut aussi essayer avec Python Tutor.
Dresser un tableau de valeurs de l'exécution du programme

Fonction sans paramètre

En principe, une fonction sans paramètre devrait avoir toujours le même comportement
Dans l'exemple suivant, on utilise un générateur pseudo-aléatoire, ce qui explique que la fonction ne renvoie pas toujours le même résultat
Une fonction pourrait aussi recevoir des données depuis l'extérieur (utilisateur, requête réseau...).

Dans ces cas, on parle de causes secondaires

In [6]: from random import randint

def lance_de() :
return randint(1,6)

compteur = 1
while lance_de() != 6:
compteur = compteur + 1
print('Obtenu un 6 en', compteur, 'jets de dé.')

Obtenu un 6 en 4 jets de dé.

Fonction sans valeur de retour

Si l'exécution arrive à la dernière instruction du corps de la fonction sans rencontrer d'instruction return expr, alors la valeur de retour par défaut
est None (même comportement si return seul)
En général une telle fonction a quand même un effet sur l'environnement (affichages, dessin, écriture dans un fichier, envoi d'informations sur le
réseau...)

Pour tous les effets autres que le renvoi d'un résultat, on parle d'effets secondaires

In [7]:
from turtle import *

def trace_polygone(nb_cotes, taille_cote):


down()
i = 0
while i < nb_cotes:
forward(taille_cote)
left(360 / nb_cotes)
i = i + 1
# faire une affectation ici ne servirait à rien (essayer !)
trace_polygone(5, 100)
exitonclick()

Erreur fréquente : confusion (paramètre / saisie) et (retour / affichage)

Les programmeurs débutants confondent très souvent la notion de paramètre et celle de saisie (au clavier par exemple) et la notion de valeur de retour
avec celle de valeur affichée.

In [8]:
# ATTENTION CECI EST INCORRECT, A NE PAS REPRODUIRE !!!
def pgcd(a, b):
a = int(input()) # NON !
b = int(input()) # NON !
while a % b != 0:
r = a % b
a = b
b = r
print("le pgcd est", b) # NON !

NE SURTOUT PAS PROGRAMMER COMME ÇA !

Comment écrire un programme vérifiant si trois entiers sont premiers entre eux à l'aide de cette fonction ?
Combien ce programme ferait-il de saisies ?
Qu'afficherait ce programme ?

In [9]: # essayons de calculer le pgcd de trois nombres


pgcd() # saisit deux nombres et calcule leur pgcd
... # je ne sais pas comment continuer !

---------------------------------------------------------------------------TypeError Traceback (most recent call las


1 # essayons de calculer le pgcd de trois nombres
----> 2 pgcd() # saisit deux nombres et calcule leur pgcd
3 ... # je ne sais pas comment continuer !
TypeError: pgcd() missing 2 required positional arguments: 'a' and 'b'

Approfondissement

Composition de fonctions

In [ ]:
def pgcd(a, b):
while a % b != 0:
r = a % b
a = b
b = r
return b

In [ ]:
def simplifier(num, denom):
d = pgcd(num, denom)
return (num // d, denom // d)

In [ ]: simplifier(8, 6)

In [ ]:
simplifier(21, 39)

In [ ]:
def pgcd3(a, b, c):
d = pgcd(a, b)
return pgcd(c, d)

In [ ]:
pgcd3(18, 27, 12)

In [ ]: pgcd3(12, 10, 15)

Fonctions et espaces de noms

Point de vigilance :

les paramètres et variables définies dans le corps d'une fonction sont indépendantes des autres variables du programme
elles n'existent plus une fois l'exécution de la fonction terminée
on les appelle des variables locales

Reprenons un exemple précédent en changeant le nom des variables :

In [ ]:
%%nbtutor -r -f

def maximum(a, b):


if a > b:
b = a
return b

nb1 = 13
nb2 = 3
c = maximum(nb1, nb2)
print("le max de", nb1, "et", nb2, "est", c)

Entraînement : Décrire l'exécution pas à pas du programme (avec état de la mémoire).

À retenir : Changer les valeurs de a et b dans la fonction n'a pas d'effet sur nb1 et nb2 !

On renomme cette fois les variables globales du programme :

In [ ]:
%%nbtutor -r -f

def maximum(a, b):


if a > b:
b = a
return b

a = 13
b = 3
c = maximum(a, b)
print("le max de", a, "et", b, "est", c)

Entraînement : Décrire l'exécution pas à pas du programme (avec état de la mémoire).

À retenir : Changer les valeurs de a et b dans la fonction n'a pas d'effet sur a et b dans le programme principal !

Autre exemple important

Essayons d'écrire une fonction permettant d'intervertir les valeurs de deux variables :

In [ ]:
# %%nbtutor -r -f # commenter si nb_tutor non installé

def echange(a, b):


temp = a
a = b
b = temp

x = 1
y = 2
echange(x, y)
print(x, y)
print(temp)

Entraînement : Décrire l'exécution pas à pas du programme (avec état de la mémoire).

À retenir :

changer les valeurs de a et b dans la fonction n'a pas d'effet sur x et y dans le programme principal !
la variable temp n'existe plus après l'exécution de la fonction

Sémantique d'un appel

Au moment d'un appel de fonction, un espace de noms local est créé. Il associe à chacun des paramètres la valeur de l'expression correspondante
dans l'appel. Les variables locales sont également créées dans ces espace de noms.

Espace de noms

Un espace de noms est un ensemble de noms (de variables, de fonctions...) défini à un certain point d'un programme

L'ensemble de tous les noms connus à un point du programme est généralement constitué de plusieurs espaces de noms superposés (du plus ancien
au plus récent) :

espace de noms prédéfini (built-in)


espace de noms global
noms définis dans le programme principal
empilement des espaces de noms locaux des appels de fonction en cours
dans l'ordre chronologique
contenant chacun les paramètres de l'appel correspondant
contenant chacun les variables locales à cette fonction

Pile d'appels

L'empilement des espaces de noms obéit à une politique de pile


sommet : appel en cours
en-dessous : appels précédents
(presque) tout en bas : espace de nom global

Dans Python Tutor : le plus récent est en bas...

Quand l'appel en cours se termine

son espace de nom est supprimé de la pile


l'exécution de l'appel précédent reprend

Quand un nouvel appel commence :

l'exécution de la fonction en cours s'interrompt


un nouvel espace de noms local est créé
l'exécution de la fonction appelée commence

Quand une erreur se produit pendant l'exécution d'un appel :

la ligne en cours de chaque appel est affiché (du plus ancien au plus récent)
nom technique : « traceback »

In [ ]: simplifier(4, 0)

Portée des variables

Accès à la valeur d'une variable :

possible pour n'importe quel nom défini dans un des espaces de noms antérieurs
si plusieurs espaces contiennent le même nom, c'est le plus récent qui est sélectionné

Affectation :

par défaut, uniquement aux variables locales


pour une variable dans un espace de nom plus ancien, mots-clés global ou nonlocal (à utiliser avec précaution)

Déroulement détaillé d'un appel

Considérons l'appel suivant :

def ma_fonction(p_1, ..., p_n):


...
return expr

# Appel de fonction (à l'intérieur d'une expression)


... ma_fonction(e_1, ..., e_n) ...

Succession des étapes de l'appel :

création d'un espace de noms local contenant p_1 à p_n au sommet de la pile d'appels
chaque expression e_i est évaluée en une valeur v_i et affectée à la variable p_i
exécution du corps de la fonction dans l'espace de noms local
si la fonction exécute l'instruction return expr ou atteint la fin de son bloc d'instructions
l'espace de noms local est détruit
l'expression appelante ma_fonction(e_1, ..., e_n) prend la valeur de expr (respectivement None)
reprise du programme principal dans l'espace global

Vocabulaire :

les noms p_1 à p_n sont appelés paramètres formels (ou paramètres tout court)
les valeurs v_1 à v_n sont appelées paramètres effectifs (ou arguments)

Documentation et test de fonctions

Chaînes de documentation (docstring)

Bonne pratique : indiquer par un commentaire

à quoi sert une fonction


ce que représentent ses paramètres et leur type
ce que représente sa valeur de retour
d'éventuels effets ou causes secondaires

In [ ]:
def triple(n):
"""
Fonction calculant le triple du nombre n (int ou float)
ou la répétition trois fois de la chaîne n.
"""
return n * 3

On peut accéder à la chaîne de documentation d'une fonction en tapant help(nom de la fonction) dans l'interpréteur :

In [ ]:
help(triple)
Cela fonctionne aussi pour les fonctions prédéfinies ou issues de modules :

In [ ]: from random import randint


help(randint)

Tests intégrés à la documentation (doctest)

Comme tout morceau de programme, chaque fonction doit être testée immédiatement pour s'assurer qu'elle fonctionne.

In [ ]: triple(3)

In [ ]:
triple(9.0)

Plutôt que de perdre ces tests, il est utile de les intégrer à la documentation de la fonction, pour pouvoir s'y référer plus tard. Si l'on change le code de
la fonction, cela permet aussi de vérifier que son comportement reste correct.

In [ ]:
def triple(n):
"""
Fonction calculant le triple du nombre n (int ou float)
ou la répétition trois fois de la chaîne n.

>>> triple(3)
9
>>> triple(9.0)
27.0
"""
return n * 3

Il existe des outils qui permettent de lancer automatiquement tous les tests présents dans la documentation, et de vérifier qu'ils produisent les
résultats annoncés.

Par exemple, à la fin d'un programme, on peut écrire le code suivant pour lancer systématiquement tous les tests présents dans le fichier :

import doctest
[Link]()

Exemple :

In [ ]: def triple(n):
"""
Fonction calculant le triple du nombre n (int ou float)
ou la répétition trois fois de la chaîne n.

>>> triple(3)
9
>>> triple(9.0)
27.0
>>> triple('pom')
'pompompom'
"""
return n * 3

In [ ]: def racine(n):
"""
Fonction calculant la racine carrée du nombre n.

>>> racine(0)
0.0
>>> racine(1)
1.0
>>> racine(4)
2.0
"""
return n ** (1/2)

In [ ]:
import doctest
[Link]()

Annotations de type

Tout ce qui suit est non exigible en contrôle.

On peut également préciser le type des paramètres et du résultat d'une fonction à l'aide d'annotations de type
Ces annotations ne sont pas vérifiées directement par Python
Elles sont utilisées par certains environnements de développement (IDE) comme PyCharm, VSCode, etc. pour fournir de l'information à
l'[Link]
Voir la documentation ici par exemple
In [ ]:
def pgcd(a: int, b: int) -> int:
while a % b != 0:
r = a % b
a = b
b = r
return b

In [ ]:
def salutation(nom: str) -> str:
return 'Bonjour ' + nom

Listes

Rappels

Objectif : désigner avec une seule variable une collection de valeurs

Liste : suite indexée (numérotée) d'objets quelconques (type list en python)

Élements "rangés" dans des "cases" numérotées de 0 à n − 1

En mémoire : tableau à n cases, chacune contenant une référence ("flèche") vers un objet

Peut contenir des objets de plusieurs types différents

Mutable : peut être modifiée, agrandie, raccourcie...

Création et affichage

Création : suite entre [ et ] d'expressions séparées par ,

In [ ]:
lst = [3, 'toto', 4.5, False, None]
print(lst)

Liste vide [] : liste ne contenant aucun objet

In [ ]: lst = []
print(lst)

Une liste peut contenir d'autres listes ! (on y reviendra)

In [ ]:
lst = ['test', [1, [2], 3]]
print(lst)

Exemple (Python tutor)


(exemple filé à exploiter tout au long du cours)

Opérations et fonctions de base

Longueur d'une liste

La longueur d'une liste (le nombre d'éléments qu'elle contient) s'obtient par la fonction len.

In [ ]:
lst = [3, 'toto', 4.5, False, None]
print(len(lst))

In [ ]: print(len([]))

Accès aux éléments

Les éléments d'une liste à n éléments sont numérotés de 0 à n − 1.


Le numéro d'un élément est appelé son indice.
L'accès à un élément donné s'appelle l'indexation.

In [ ]:
lst = [3, 'toto', 4.5]
print(lst[1])
Attention !

Le premier élément d'une liste est l'élément d'indice 0 !


Si la liste a n éléments, il n'existe pas d'élément d'indice n !
L'accès à un indice supérieur ou égal à la taille de la liste provoque une erreur !

In [ ]:
lst = [3, 'toto', 4.5]
print(lst[3])

Exercice : Écrire une fonction qui affiche tous les éléments d'une liste (un par ligne).

In [ ]:
def affiche_elements(lst):
...

lst = [3, 'toto', 4.5]


affiche_elements(lst)

In [ ]:
# Solution avec une boucle while
def affiche_elements(lst):
i = 0
while i < len(lst):
print(lst[i])
i = i + 1

lst = [3, 'toto', 4.5]


affiche_elements(lst)

La boucle for

Parcours de liste avec une boucle while

ma_liste = ...
i = 0
while i < len(ma_liste):
faire_un_truc_avec(i)
i += 1

Inconvénients :

Oubli fréquent de l'incrémentation de i (surtout si le corps de la boucle est long)


Erreurs possibles dans l'initialisation et le test

Parcours de liste élément par élément avec une boucle for (itération)

ma_liste = ...
for elem in ma_liste:
faire_un_truc_avec(elem)

Avantages :

Absence des inconvénients du while...


Code plus lisible (pas de [i])

Inconvénient :

Pas d'accès à l'indice courant

Exercice : Écrire une fonction qui affiche tous les éléments d'une liste (un par ligne) avec une boucle for.

In [25]:
def affiche_elements(lst):
for elem in lst:
print(elem)

lst = [3, 'toto', 4.5]


affiche_elements(lst)

3
toto
4.5

Parcours de liste par indices avec une boucle for

On peut aussi parcourir une liste par indices avec une boucle for, à l'aide de la fonction range(). Pour l'instant, il suffit de savoir que la fonction range
fabrique des intervalles d'entiers :

range(i) : entiers de 0 à i-1


range(i, j) : entiers de i à j-1
range(i, j, k) : entiers de i à j-1 par pas de k
Dans la section sur les itérables, nous reviendrons en détail sur range().
In [26]:
def affiche_elements(lst):
for i in range(len(lst)):
print(lst[i])

lst = [3, 'toto', 4.5]


affiche_elements(lst)

3
toto
4.5

C'est particulièrement utile lorsque l'on a besoin d'accéder à l'indice (on y reviendra).

Nota bene : dans toute la suite, lorsqu'il s'agit de coder une fonction sur une liste, on vous présente la version avec un while et avec un for (par
éléments ou par indices suivant les cas), en mettant en premier celle qui est la plus élégante.

Modification d'un élément

On peut modifier le i-ème élément de lst à l'aide d'une affectation :

In [ ]:
lst = [3, 'toto', 4.5, False, None]
print(lst[2])
lst[2] = 'titi'
print(lst)

Attention, ceci ne crée pas une nouvelle liste mais modifie la liste sur place !

In [ ]:
lst = [3, 'toto', 4.5, False, None]
lst_bis = lst
lst[2] = 'titi'
lst_bis

Concaténation et répétition

Comme pour les chaînes de caractères (str) on peut utiliser les opérateurs + pour fabriquer la concaténation de deux listes et * pour répéter une liste.

In [ ]: [3, 'toto', 4.5] + [False, None]

In [ ]:
[] + [3, 'toto', 4.5] + []

In [ ]:
3 * ['a', 'b']

In [ ]: [0] * 13

On peut utiliser ces opérateurs pour recopier une liste. Comparer :

In [ ]:
lst = [3, 'toto', 4.5]
lst2 = lst
lst3 = lst + []
lst4 = lst * 1

Test d'appartenance

Exercice : Écrire une fonction recevant une liste et une valeur, et renvoyant True si la valeur apparaît dans la liste (False sinon)

In [11]:
def appartient(lst, val):
...

Avec un for :

In [13]:
def appartient(lst, val):
for elem in lst:
if elem == val:
return True
return False

lst = ['Hildegarde', 'Cunégonde', 'Médor']


print(appartient(lst, 'Cunégonde'))

if appartient(lst, 'Médor'):
print('Bon chien !')

True
Bon chien !

Avec un while (moins lisible) :

In [12]: def appartient(lst, val):


i = 0
while i < len(lst):
if lst[i] == val:
return True
i += 1
return False

lst = ['Hildegarde', 'Cunégonde', 'Médor']

print(appartient(lst, 'Cunégonde'))

if appartient(lst, 'Médor'):
print('Bon chien !')

True
Bon chien !

Remarque : Cette fonctionnalité existe déjà en Python :

val in lstvaut True si val apparaît dans lst, False sinon


Réciproquement, on peut écrire val not in lst

In [ ]:
lst = ['Hildegarde', 'Cunégonde', 'Médor']
'Cunégonde' in lst

In [ ]: lst = ['Hildegarde', 'Cunégonde', 'Médor']


'Rex' not in lst

In [ ]:
lst = ['Hildegarde', 'Cunégonde', 'Médor']
if 'Médor' in lst:
print('Bon chien !')

Minimum et maximum d'une liste

Exercice : Écrire une fonction recevant une liste non vide d'éléments comparables entre eux et renvoyant la valeur du plus petit élément qui apparaît
dans la liste

In [14]:
def minimum(lst):
...

Même question pour le plus grand élément

In [15]:
def maximum(lst):
...

Avec un for :

In [19]: def minimum(lst):


res = lst[0] # plante si lst == []
for elem in lst:
if elem < res:
res = elem
return res

In [22]:
def maximum(lst):
res = lst[0]
for elem in lst:
if elem > res:
res = elem
return res

In [23]:
lst = [4, 6.6, 2, -7, 13, -6, 0]
print(minimum(lst), maximum(lst))

-7 13

Avec un while :

In [16]:
def minimum(lst):
res = lst[0] # plante si lst == []
i = 1
while i < len(lst):
if lst[i] < res:
res = lst[i]
i += 1
return res

In [17]:
def maximum(lst):
res = lst[0]
i = 1
while i < len(lst):
if lst[i] > res:
res = lst[i]
i += 1
return res

In [18]:
lst = [4, 6.6, 2, -7, 13, -6, 0]
print(minimum(lst), maximum(lst))

-7 13

Ces fonctionnalités existent déjà en Python : fonctions min et max.

In [ ]:
lst = [4, 6.6, 2, -7, 13, -6, 0]
print(min(lst), max(lst))

Attention : pour que cela fonctionne il faut que tous les éléments soient comparables !

In [ ]:
lst = [3, 'toto', 4.5, False, None]
print(min(lst))

Une erreur se produit aussi si l'on appelle ces fonctions sur une liste vide :

In [24]:
min([])

---------------------------------------------------------------------------ValueError Traceback (most recent call las


----> 1 min([])
ValueError: min() arg is an empty sequence

Somme des éléments d'une liste

Exercice : Écrire une fonction somme(lst) qui renvoie la somme des éléments d'une liste dont tous les éléments sont des nombres.

In [ ]:
def somme(lst):
...

Avec un for :

In [28]:
def somme(lst):
res = 0
for elem in lst:
res += elem
return res

print(somme([1, 2, 3]))

Avec un while :

In [ ]:
def somme(lst):
res = 0
i = 0
while i < len(lst):
res += lst[i]
i += 1
return res

print(somme([1, 2, 3]))

La fonction prédéfinie sum de Python réalise également ce calcul :

In [ ]:
sum([1, 2, 3])

Attention : la fonction sum provoque une erreur si un élément de la liste n'est pas un nombre !

In [ ]:
sum([3, 'toto', 4.5, False, None])

Manipulations plus complexes : méthodes

On va maintenant énumérer un certain nombre de méthodes prédéfinies sur les listes, permettant des modifications plus complexes. Pour plus de
détails, on pourra consulter la documentation en ligne.

Agrandir ou rétrécir une liste

Plusieurs instructions ont un effet sur la taille de la liste :

L'instruction [Link](elem) ajoute l'élément elem à la fin de la liste lst

L'instruction [Link]() supprime le dernier élément de lst et renvoie sa valeur

L'instruction [Link](i) supprime l'élément d'indice i de lst et renvoie sa valeur

Les fonctions append et pop sont appelées méthodes, ou fonctions s'appliquant à un objet (nous en verrons d'autres dans les cours suivants)

Attention, ces instructions ne créent pas une nouvelle liste mais modifient la liste sur place !

Attention, ne pas confondre x = lst[2] et x = [Link](2) !

In [ ]:
lst = [3, 'toto', 4.5, False, None]
lst_bis = lst

[Link](1)
print(lst_bis)

elem = lst_bis.pop(2)
print(elem)

print(lst)

Exercice : écrire une fonction recevant deux listes et ajoutant tous les éléments de la seconde à la fin de la première

In [ ]:
def etend_liste(une_liste, autre_liste):
...

Attention, pas de return : une_liste doit être modifiée sur place !

Attention, on ne doit pas modifier autre_liste !

Avec un for :

In [29]:
def etend_liste(une_liste, autre_liste):
for elem in autre_liste:
une_liste.append(elem)

lst = [3, 'toto', 4.5]


lst2 = [False, None]

print(lst)
print(lst2)
etend_liste(lst, lst2)
print(lst)
print(lst2)

[3, 'toto', 4.5]


[False, None]
[3, 'toto', 4.5, False, None]
[False, None]

Avec un while :
In [ ]:
def etend_liste(une_liste, autre_liste):
i = 0
while i < len(autre_liste):
une_liste.append(autre_liste[i])
i += 1

lst = [3, 'toto', 4.5]


lst2 = [False, None]

print(lst)
print(lst2)
etend_liste(lst, lst2)
print(lst)
print(lst2)

Cette fonctionnalité existe déjà en Python : une_liste.extend(autre_liste)

In [ ]: lst = [3, 'toto', 4.5]


lst_bis = lst
lst2 = [False, None]

[Link](lst2)
print(lst)
print(lst_bis)

In [ ]:
lst = [3, 'toto', 4.5]
lst_bis = lst
lst2 = [False, None]

lst = lst + lst2


print(lst)
print(lst_bis)

Exercice : Écrire une fonction recevant deux listes en argument et renvoyant une nouvelle liste contenant tous les éléments de la première suivis de
tous les éléments de la seconde, à la manière de l'opérateur +.

In [ ]:
def concatene(lst1, lst2):
...

Ici, le plus simple est de réutiliser les fonctions précédentes :

In [30]: def concatene(lst1, lst2):


res = []
[Link](lst1)
[Link](lst2)
return res

concatene([3, 1, 67], [2, 4])

Out [30]: [3, 1, 67, 2, 4]

On peut aussi s'en sortir avec un for :

In [31]:
def concatene(lst1, lst2):
res = []
for elem1 in lst1:
[Link](elem1)
for elem2 in lst2:
[Link](elem2)
return res

concatene([3, 1, 67], [2, 4])

Out [31]: [3, 1, 67, 2, 4]

Ou avec un while :

In [ ]: def concatene(lst1, lst2):


res = []
i = 0
while i < len(lst1):
[Link](lst1[i])
i += 1
i = 0
while i < len(lst2):
[Link](lst2[i])
i += 1
return res

concatene([3, 1, 67], [2, 4])

Exercice : Écrire une fonction recevant une liste lst et un entier n en argument et renvoyant une nouvelle liste contenant les éléments de lst répétés n
fois à la manière de l'opérateur *.

In [32]:
def repete(lst, n):
...

Ici, le plus simple est à nouveau de réutiliser les fonctions précédentes :

In [33]:
def repete(lst, n):
res = []
i = 0
while i < n:
[Link](lst)
i += 1
return res

repete([4, 5, 6], 3)

Out [33]: [4, 5, 6, 4, 5, 6, 4, 5, 6]

On peut aussi utiliser une boucle for pour répéter une opération n fois en parcourant les entiers de 0 à n-1 ou de 1 à n grâce à range() :

In [34]:
def repete(lst, n):
res = []
for i in range(n):
[Link](lst)
return res

repete([4, 5, 6], 3)

Out [34]: [4, 5, 6, 4, 5, 6, 4, 5, 6]

Comme d'habitude, on peut aussi s'en sortir avec seulement des while, même si c'est moins élégant :

In [35]:
def repete(lst, n):
res = []
i = 0
while i < n:
j = 0
while j < len(lst):
[Link](lst[j])
j += 1
i += 1
return res

repete([4, 5, 6], 3)

Out [35]: [4, 5, 6, 4, 5, 6, 4, 5, 6]

Rechercher la position d'un élément

Exercice : Écrire une fonction renvoyant le plus petit indice où apparaît un élément x dans une liste lst (on renverra None si x n'apparaît pas dans la
liste)

In [ ]:
def chercher(lst, x):
...

Avec un while :

In [ ]: def chercher(lst, val):


i = 0
while i < len(lst):
if lst[i] == val:
return i
i += 1
return None

lst = [3, 'toto', 4.5, False, None, 4.5]


indice = chercher(lst, 4.5)
print(indice)
indiceNone = chercher(lst, 'AP1')
print(indiceNone)

Exercice : Même exercice que ci-dessus, mais avec une boucle for.

Problème : la boucle for par éléments ne permet pas d'accéder à l'indice de x !

Solution : itérer sur un intervalle d'indices à l'aide de la fonction range().

In [ ]:
def chercher(lst, val):
for i in range(len(lst)):
if lst[i] == val:
return i
return None

lst = [3, 'toto', 4.5, False, None, 4.5]


indice = chercher(lst, 4.5)
print(indice)
indiceNone = chercher(lst, 'AP1')
print(indiceNone)

Cette fonction existe déjà en Python : méthode index

In [ ]: lst = [3, 'toto', 4.5, False, None, 4.5]


[Link](4.5)

Attention, cette méthode provoque une erreur si l'élément recherché n'est pas dans la liste !

In [ ]:
lst = [3, 'toto', 4.5, False, None, 4.5]
[Link](3.5)

Compter le nombre d'occurrences d'un élément

Exercice : Écrire une fonction renvoyant le nombre de fois où apparaît un élément x dans une liste lst

In [ ]: def compter(lst, x):


...

Avec un for :

In [36]:
def compter(lst, x):
cpt = 0
for elem in lst:
if elem == x:
cpt += 1
return cpt

lst = [3, 'toto', 4.5, False, None, 4.5]


print(compter(lst, 4.5))

Avec un while :

In [ ]:
def compter(lst, x):
cpt = 0
i = 0
while i < len(lst):
if lst[i] == x:
cpt += 1
i += 1
return cpt
lst = [3, 'toto', 4.5, False, None, 4.5]
print(compter(lst, 4.5))

Cette fonction existe déjà en Python : méthode count

In [ ]:
lst = [3, 'toto', 4.5, False, None, 4.5]
[Link](4.5)

Vider entièrement une liste

Exercice : Écrire une fonction supprimant tous les éléments de la liste lst

In [ ]: def vider(lst, x):


...

In [ ]:
def vider(lst):
while len(lst) > 0:
[Link]()

lst = [3, 'toto', 4.5, False, None, 4.5]


print(lst)
vider(lst)
print(lst)

Cette fonction existe déjà en Python : méthode clear

In [ ]:
lst = [3, 'toto', 4.5, False, None, 4.5]
[Link]()
print(lst)

Que se passe-t-il si l'on essaie de le faire avec une boucle for ?

In [38]:
# ATTENTION : MAUVAISE SOLUTION
def essaie_de_vider_pour_voir(lst):
for i in range(len(lst)):
[Link](i)

lst = [3, 'toto', 4.5, False, None, 4.5]


print(lst)
essaie_de_vider_pour_voir(lst)
print(lst)

[3, 'toto', 4.5, False, None, 4.5]

---------------------------------------------------------------------------IndexError Traceback (most recent call las


6 lst = [3, 'toto', 4.5, False, None, 4.5]
7 print(lst)
----> 8 essaie_de_vider_pour_voir(lst)
9 print(lst)
/tmp/ipykernel_45904/[Link] in essaie_de_vider_pour_voir(lst)
2 def essaie_de_vider_pour_voir(lst):
3 for i in range(len(lst)):
----> 4 [Link](i)
5
6 lst = [3, 'toto', 4.5, False, None, 4.5]
IndexError: pop index out of range

On pourrait tout de même s'en sortir, mais lorsque l'on souhaite faire une fonction qui modifie la liste donnée en argument, il vaut généralement mieux
le faire avec une boucle while.

Renverser une liste

Exercice : Écrire une fonction renversant l'ordre des éléments d'une liste lst

In [ ]:
def renverser(lst, x):
...

In [ ]:
def renverser(lst):
i = 0
j = len(lst) - 1
while i < j:
lst[i], lst[j] = lst[j], lst[i]
i += 1
j -= 1

lst = [3, 'toto', 4.5, False, None, 4.5]


renverser(lst)
print(lst)

Cette fonction existe déjà en Python : méthode reverse

In [ ]:
lst = [3, 'toto', 4.5, False, None, 4.5]
[Link]()
print(lst)

Ici aussi, comme il s'agit de modifier la liste, on utilise un while (idem dans la suite).

Retirer un élément donné

Exercice : Écrire une fonction retirant la première occurrence d'un élément x dans une liste lst (on ne fera rien si la liste ne contient pas x)

In [ ]:
def retirer(lst, x):
...

In [ ]: def retirer(lst, x):


i = chercher(lst, x)
if i is not None:
while i < len(lst)-1:
lst[i] = lst[i+1]
i += 1
[Link]()

lst = [3, 'toto', 4.5, False, None, 4.5]


print(lst)
retirer(lst, 4.5)
print(lst)

In [ ]:
def retirer2(lst, x): # version utilisant pop(i)
i = chercher(lst, x)
if i is not None:
[Link](i)

lst = [3, 'toto', 4.5, False, None, 4.5]


print(lst)
retirer2(lst, 4.5)
print(lst)

Cette fonction existe déjà en Python : méthode remove

In [ ]:
lst = [3, 'toto', 4.5, False, None, 4.5]
[Link](4.5)
print(lst)

Attention, cette méthode provoque une erreur si l'élément à retirer n'est pas dans la liste !

In [ ]:
lst = [3, 'toto', 4.5, False, None, 4.5]
[Link](3.5)

Ajouter un élément donné à un indice donné

Exercice : Écrire une fonction qui insère un élément x à la position i de la liste lst (si i est trop grand, la fonction insère x à la fin de lst ; si i est trop
petit, elle insère x au début de lst)

In [ ]:
def ajouter(lst, i, x):
...

In [ ]:
def ajouter(lst, i, x):
# determine une valeur correcte pour i
i = max(0, min(i, len(lst)))
# on ajoute une case vide à la fin
[Link](None)
# decalage des cases sur la droite à partir de i
j = len(lst) - 1
while j > i:
lst[j] = lst[j-1]
j -= 1
lst[i] = x # on insère x à l'indice i
lst = [3, 'toto', 4.5, False, None, 4.5]
print(lst)
ajouter(lst, 3, 79) # indice ok
print(lst)
ajouter(lst, -6, "petit") # indice trop petit
print(lst)
ajouter(lst, 16, "grand") # indice trop grand
print(lst)

Cette fonction existe déjà en Python : méthode insert

Attention, cette méthode insère l'élément à la fin si l'indice est supérieur à len(lst), et au début si l'indice est négatif !

In [ ]:
lst = [3, 'toto', 4.5, False, None, 4.5]
print(lst)
[Link](3, 79)
print(lst)

In [ ]:
[Link](-8, "petit")
print(lst)
[Link](16, "grand")
print(lst)

Trier une liste

Enfin, il est possible de trier le contenu d'une liste avec la méthode sort. Programmer ce genre de fonctions fait partie des objectifs du semestre 2.

In [ ]: lst = [4, 6.6, 2, -7, 13, -6, 0]


[Link]()
print(lst)

Attention, cette méthode ne fonctionne pas si les éléments ne sont pas tous comparables !

In [ ]: lst = [3, 'toto', 4.5, False, None, 4.5]


[Link]()

Notez que la méthode sort modifie définitivement la liste (une nouvelle liste n'est pas créée). Il existe aussi une fonction permettant de fabriquer une
copie triée d'une liste : la fonction sorted.

In [ ]:
lst = [4, 6.6, 2, -7, 13, -6, 0]
print(sorted(lst))
print(lst)

Récapitulatif

Opérateurs sur les listes

opérateur effet
lst[i] (dans une expression) élément d'indice i de lst
lst[i] = expr modifie l'élément d'indice i de lst
lst1 + lst2 concaténation (nouvelle liste)
lst * n répétition (nouvelle liste)
x in lst True si x apparaît dans lst
x not in lst True si x n'apparaît pas dans lst

⋆ : erreur si i n'est pas un indice correct de lst

Fonctions sur les listes

fonction effet
len(lst) renvoie la longueur de lst
min(lst) renvoie le plus petit élément de lst ⋆♡
max(lst) renvoie le plus grand élément de lst ⋆♡
sum(lst) renvoie la somme des éléments de lst ♣
sorted(lst) renvoie une copie triée de lst ♡

⋆ : erreur si lst est vide


♡ : erreur si lst contient des éléments incomparables
♣ : ne fonctionne que sur des listes de nombres
Méthodes qui modifient la liste

méthode effet
[Link](x) ajoute x à la fin de lst
[Link](lst2) ajoute les éléments de lst2 à la fin de lst
[Link](i, x) ajoute x à l'indice i dans lst
[Link](x) retire la première occurrence de x de lst ⋆
[Link]() retire et renvoie le dernier élément de lst ♣
[Link](i) retire et renvoie l'élément d'indice i de lst ♡
[Link]() vide la liste
[Link]() trie la liste ♢
[Link]() renverse la liste

⋆ : erreur si lst ne contient pas x


♣ : erreur si lst est vide
♡ : erreur si l'indice i n'existe pas dans lst
♢ : erreur si lst contient des éléments incomparables

Méthodes qui ne modifient pas la liste

méthode effet
[Link](x) renvoie l'indice de la première occurrence de x dans lst ⋆
[Link](x) renvoie le nombre d'occurrences de x dans lst ⋆
[Link]() renvoie une copie (superficielle !) de lst ♣

⋆ : erreur si lst ne contient pas x



: superficielle veut dire que les éléments ne sont pas recopiés

Consulter la documentation en ligne pour plus de détails.

for vs while
Le fichier recap_fonctions_listes.py est un récapitulatif des fonctions que l'on a vues, implémentées avec un for et avec un while. La version préférée
est en premier.

Quand utiliser tel ou tel type de boucle ?

Voir le fichier types_boucles.py.

Manipulation de sous-listes : les slices (tranches)


La connaissance de cette notion n'est pas exigible à l'examen.

Accès à une slice

Syntaxe : lst[i, j] construit une liste contenant les éléments d'indices i à j-1 de lst
Attention, l'élément d'indice i est inclus mais celui d'indice j est exclu !

In [ ]:
lst = [3, 'toto', 4.5]
print(lst[1:len(lst)])
print(lst[0:1])

Si i est omis, il prend la valeur par défaut 0


Si j est omis, il prend la valeur par défaut len(lst)

In [ ]:
lst = [3, 'toto', 4.5]
print(lst[:len(lst)-1])
print(lst[:]) # cette instruction crée une copie de lst !

Affectation de slice

On peut aussi utiliser la syntaxe des tranches pour modifier en une seule fois une partie de la liste

In [ ]: lst = [3, 'toto', 4.5]


lst[1:3] = ["riri", "fifi", "loulou"]
print(lst)

Tranches avec intervalle

Il est possible de compléter la notation des tranches en spécifiant un "pas" k: lst[i:j:k]. Dans ce cas, on sélectionne uniquement les éléments
d'indices i, i+k, i+2*k, etc. en s'arrêtant à l'indice j(exclu).

In [ ]: lst = [0, 1, 2, 3, 4, 5]
print(lst[Link])
Un exemple un peu étrange :

In [ ]:
lst = [0, 1, 2, 3, 4, 5]
print(lst[Link]-1])

Indices négatifs
La connaissance de cette notion n'est pas exigible à l'examen.

Il est possible d'utiliser des indices négatifs pour accéder aux éléments d'une liste. Dans ce cas, les éléments sont numérotés à partir de la droite, en
commençant par l'indice -1 et jusqu'à l'indice -len(lst) :

In [ ]:
lst = [3, 'toto', 4.5]
print(lst[-1])
print(lst[-3])

On voit que lst[-1] est une autre façon de désigner l'élément lst[len(lst)-1, et lst[-len(lst)] désigne lst[0]. Tenter d'accéder à un indice plus
petit provoque une erreur :

In [ ]:
lst = [3, 'toto', 4.5]
print(lst[-4])

Ces indices négatifs sont utiles comme raccourcis d'écriture dans certains cas particuliers, par exemple pour construire la copie d'une liste privée de
son dernier élément :

In [ ]:
lst = [3, 'toto', 4.5]
print(lst[:-1])

Un autre type de parcours de liste : enumerate

La connaissance de cette notion n'est pas exigible à l'examen.

La fonction enumerate(iterable) permet d'itérer sur les couples (i, elem) constitués d'un indice et de l'élément correspondant dans iterable.

In [14]:
def chercher(L, x):
for i, elem in enumerate(L):
if elem == x:
return i
return None

In [ ]:
def lister(lst):
for i, elem in enumerate(lst):
print(i, '->', elem)

lister([6, 3, 8])

Mutations de listes

La connaissance de cette notion n'est pas exigible à l'examen.

Il existe une syntaxe abrégée, inspirée de la notation ensembliste des mathématiques, qui permet de définir rapidement des listes. On parle de
mutations de listes, ou list comprehensions en Anglais.

La syntaxe est :

lst = [<forme d'un élement> for <variable> in <iterable>]

Cette écriture est équivalente à la syntaxe habituelle suivante :

lst = []
for <variable> in <iterable>:
[Link](<forme d'un element>)

On peu aussi rajouter une condition :

lst = [<forme d'un élement> for <variable> in <iterable> if <condition>]

Ce qui équivaut à :

lst = []
for <variable> in <iterable>:
if <condition>:
[Link](<forme d'un element>)

Voici quelques exemples :

In [16]:
[i*i for i in range(10)] # liste des 10 premiers carrés
Out [16]: [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

In [17]: lst = []
for i in range(10):
[Link](i*i)
lst

Out [17]: [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

In [ ]: [i*i for i in range(10) if i*i % 2 == 0]

In [ ]:
[c for c in 'anticonstitutionnellement' if c in 'aeiouy'] # liste des voyelles d'un mot

On peut aussi utiliser plusieurs boucles et conditions :

lst = [<forme d'un élement>


for <variable1> in <iterable1>
for <variable2> in <iterable2>
if <condition>]

Ce qui équivaut à :

lst = []
for <variable1> in <iterable1>:
for <variable2> in <iterable2>:
if <condition>:
[Link](<forme d'un element>)

Exemple :

In [ ]: [(x, y) for x in [1,2,3] for y in [3,1,4] if x != y]

On peut également imbriquer les expressions de ce type :

In [ ]:
[[i + j for j in range(5)] for i in range(5)]

Listes de listes
Une liste peut contenir des éléments de n'importe quel type, en donc en particulier des listes, voire des listes de listes, etc.

Exemple : le morpion

Les listes de listes sont particulièrement adaptées lorsque l'on souhaite représenter des grilles carrées ou rectangulaires. C'est le cas du morpion, qui
se joue sur une grille 3x3 (voir aussi l'exercice "retournement", TD 6 ex.1). Par exemple, la grille (les points représentent des cases vides) :

...X.X.O.

Peut être représentée par la liste de liste :

In [ ]:
grille = [['.', '.', '.'], ['X', '.', 'X'], ['.', 'O', '.']]

La case de coordonnées (i, j) correspond alors à grille[i][j] (attention : comme d'habitude, la numérotation commence à 0). Graphiquement :

0120...1X.X2.O.

On peut expérimenter :

In [ ]:
grille[2][1] # Vous pouvez faire varier les indices

On peut aussi modifier le contenu des cases :

In [ ]: grille[2][2] = 'O'
grille

Copie superficielle

Pour des raisons d'efficacité, Python est flemmard : lorsqu'on met une liste dans une variable, la liste n'est pas copiée, et la variable est simplement un
alias.

In [ ]:
liste = [1, 2, 3]
fausse_copie = liste
fausse_copie[1] = 4
print(fausse_copie)
print(liste)
# fausse_copie et liste sont toutes deux modifiées !

C'est très instructif d'aller voir ce qu'il se passe mémoire sur PythonTutor : fausse_copie et liste pointent vers la même liste.
Cela vaut aussi pour les listes de listes ! Par exemple :
In [ ]:
ligne = [1, 2, 3]
grille = []
for i in range(3):
[Link](ligne)
# Équivalent à grille = [ligne] * 3
grille[2][1] = 4
print(grille)
# Le contenu des trois lignes est modifié, puisque c'est la *même* liste

Fonctions qui modifient des listes

Retour sur le modèle de mémoire

Pour bien comprendre cette section, il est utile de revoir la section "Modèle de mémoire de Python" de la séquence 1 du cours. Ainsi, chaque variable
est en fait le nom d'une flèche vers un objet en mémoire : [Link].

Souvenez-vous de cet exemple :

In [ ]:
def essaie_de_modifier_pour_voir(x):
x = 5

x = 12
essaie_de_modifier_pour_voir(x)
print(x)

La valeur de x n'est pas modifiée ! En effet, la fonction reçoit seulement la valeur de x, qui est 12, et le x dans la fonction est cantonné à l'espace de
noms local (ce n'est pas le même x).

Plus généralement, une fonction ne peut pas faire en sorte qu'une variable pointe vers un autre objet en mémoire :

In [ ]:
def essaie_de_modifier_pour_voir_2(x):
x = [5]

x = [12]
essaie_de_modifier_pour_voir_2(x)
print(x)

Ça marche aussi pour les autres types :

In [ ]: def essaie_de_modifier_pour_voir_3(x):
x = "5"

x = "12"
essaie_de_modifier_pour_voir_3(x)
print(x)

Les types primitifs sont immutables

Puisqu'il est impossible qu'une fonction fasse en sorte que son argument pointe vers un autre objet, on pourrait être tenté de modifier cet objet.

Ici, le comportement dépend du type de l'objet. Pour les int, float et bool, on ne voit pas bien comment on pourrait les modifier. Qu'en est-il des
chaînes de caractères (str) ? Essayons :

In [ ]:
def essaie_de_modifier_pour_voir_chaine(x):
x[0] = "C"

x = "Zoucou les AP1 !"


essaie_de_modifier_pour_voir_chaine(x)
print(x)

Python explose avec l'erreur TypeError: 'str' object does not support item assignment. En effet, il interdit aussi formellement de modifier les
chaînes de caractères.

On dit que int, float, bool et str sont immutables.

In [ ]:
x = "Zoucou les AP1 !"
x[0] = "C"
# Même erreur

Cela n'interdit bien sûr pas de réassigner les variables :

In [ ]:
x = "Zoucou les AP1 !"
x = "Coucou les AP1 !"
print(x)

En effet, ici, Python crée un nouvel objet "Coucou les AP1 !" et fait en sorte que x pointe vers ce nouvel objet. L'ancien objet "Zoucou les AP1 !" n'est
pas modifié (mais n'a plus personne qui pointe vers lui).

Les listes sont mutables

Les listes se comportent différemment ! Par exemple :

In [ ]:
liste = [1, 2, 3]
liste[2] = 4
print(liste)

Ou encore :

In [ ]: x = list("Zoucou les AP1 !") # list convertit son argument en liste


print(x)
x[0] = "C"
print(x)

Par conséquent, les fonctions peuvent aussi modifier les listes qu'elles prennent en argument :

In [ ]:
def essaie_de_modifier_pour_voir_liste(x):
x[0] = 5

x = [12]
essaie_de_modifier_pour_voir_liste(x)
print(x)

On observe que le contenu de la liste x est modifié ! En effet, la fonction reçoit en argument la valeur de la variable x, qui est la liste elle-même (x est
seulement un nom pour la flèche vers la liste). Elle peut donc en modifier le contenu de la liste via x[0] = 5, qui exécute une action sur la liste.

On dit que les listes sont mutables.

Attention cependant ! Comme vu ci-dessus, on ne peut pas modifier directement x en tant que variable, par exemple en lui demandant de pointer vers
une autre liste :

In [ ]:
def essaie_de_modifier_pour_voir_liste_bis(x):
x = [5]

x = [12]
essaie_de_modifier_pour_voir_liste_bis(x)
print(x)

Observez que c'est cohérent avec le comportement de la fonction essaie_de_modifier_pour_voir.

Séquences et itérables
Les itérables sont toutes les structures de données dont on peut parcourir les éléments un par un, c'est-à-dire que l'on peut itérer.

Nous avons déjà vu les listes.

Exercice (rappel) :

Implémenter les fonctions compter, copier et chercher en utilisant des boucles for

In [1]:
def compter(L, x):
cpt = 0
for elem in L:
if elem == x:
cpt += 1
return cpt

In [2]: compter([0, 0, 1, 0, 1, 1, 0], 1)

Out [2]: 3

In [3]:
def copier(L):
copie = []
for elem in L:
[Link](elem)
return copie
In [ ]:
def chercher(L, x):
for elem in L:
if elem == x:
return ... # ???
# impossible de terminer, on a besoin d'un indice
return None

Problème : pas d'accès à l'indice de x !

Solution : itérer sur un intervalle d'indices avec la fonction range().

Intervalles d'entiers : range


Comme vu précédemment, la fonction range fabrique des intervalles d'entiers :

range(i) : entiers de 0 à i-1


range(i, j) : entiers de i à j-1
range(i, j, k) : entiers de i à j-1 par pas de k

Nous allons maintenant explorer en détail l'itérable qu'elle produit (un range donc).

Opérations autorisées sur un range r:

x in r, x not in r, r[i]
len(r), min(r), max(r), [Link](x), [Link](x)
list(r) (conversion en liste)

In [4]:
r = range(10)
print(r)

range(0, 10)

In [5]:
r[0]

Out [5]: 0

In [7]:
r[1]

Out [7]: 1

In [8]:
max(r)

Out [8]: 9

In [9]: r = range(10, 30, 7)


max(r)

Out [9]: 24

In [10]: len(r)

Out [10]: 3

In [11]:
list(r)

Out [11]: [10, 17, 24]

Opérations interdites sur un range : tout le reste

Concaténation, répétition, affectation d'élément


Autres méthodes de listes (append, etc.)

Objets de type range :

séquences (comme les listes)


itérables (utilisables dans un for, comme les listes)
non mutables (non modifiables, pas comme les listes)

In [12]:
for i in range(4):
print(i)

0
1
2
3

Caractéristique importante :

Non construit entièrement en mémoire


range(10000) ne prend pas plus de place et ne prend pas plus de temps à construire que range(2)
Éléments fabriqués « à la demande »

Utilisation fréquente : parcours des indices d'une liste


In [13]:
L = ['a', 'b', 'c']
for i in range(len(L)):
print(i, '->', L[i])

0 -> a
1 -> b
2 -> c

Exercice : Écrire une fonction chercher(L, x) qui recherche la première position de x dans L en utilisant une boucle for et la fonction range.

In [ ]: def chercher(L, x):


for i in range(len(L)):
if L[i] == x:
return i
return None

Retour sur les chaînes de caractères (type str)

Les chaînes de caractères (str) sont aussi des séquences (et des itérables) !

Type str : séquence non mutable et itérable de caractères

En tant que séquences, les chaînes autorisent :

s[i] : accès à un caractère par son indice


len(s) : longueur
min(s), max(s) : minimum et maximum
s1 in s2, s1 not in s2 : recherche de sous-chaîne
[Link](s1) : position de sous-chaîne
[Link](s1) : comptage de sous-chaînes
s1 + s2, s * 3 : concaténation et répétition

En tant que séquences immutables, les chaînes interdisent :

[Link]('a'), [Link](s2), [Link](i, x), [Link](), [Link](i), [Link](x), [Link](), s[i] = x, [Link](), [Link]()...

En tant qu'objets itérables, les chaînes peuvent être utilisées dans des boucles for :

In [18]:
s = 'Hildegarde'
# afficher les caractères de s, un par ligne
for c in s:
print(c)

H
i
l
d
e
g
a
r
d
e

... et acceptent la conversion en liste :

In [19]:
s = 'Hildegarde'
list(s)

Out [19]: ['H', 'i', 'l', 'd', 'e', 'g', 'a', 'r', 'd', 'e']

Méthodes sur les chaînes

De très nombreuses méthodes existent sur les chaînes :

In [20]:
dir("")

Out [20]: ['__add__',


'__class__',
'__contains__',
'__delattr__',
'__dir__',
'__doc__',
'__eq__',
'__format__',
'__ge__',
'__getattribute__',
'__getitem__',
'__getnewargs__',
'__gt__',
'__hash__',
'__init__',
'__init_subclass__',
'__iter__',
'__le__',
'__len__',
'__lt__',
'__mod__',
'__mul__',
'__ne__',
'__new__',
'__reduce__',
'__reduce_ex__',
'__repr__',
'__rmod__',
'__rmul__',
'__setattr__',
'__sizeof__',
'__str__',
'__subclasshook__',
'capitalize',
'casefold',
'center',
'count',
'encode',
'endswith',
'expandtabs',
'find',
'format',
'format_map',
'index',
'isalnum',
'isalpha',
'isascii',
'isdecimal',
'isdigit',
'isidentifier',
'islower',
'isnumeric',
'isprintable',
'isspace',
'istitle',
'isupper',
'join',
'ljust',
'lower',
'lstrip',
'maketrans',
'partition',
'removeprefix',
'removesuffix',
'replace',
'rfind',
'rindex',
'rjust',
'rpartition',
'rsplit',
'rstrip',
'split',
'splitlines',
'startswith',
'strip',
'swapcase',
'title',
'translate',
'upper',
'zfill']

Nous les découvrirons au fur et à mesure (et pas toutes). Si vous êtes curieux... pensez à la doc ! En voici quelques unes :

[Link]() : renvoie une copie de la chaîne avec son premier caractère en majuscule et le reste en minuscule.
[Link](sub) : donne la première la position dans la chaîne où sub est trouvé
[Link](iterable) : donne une chaîne qui est la concaténation des chaînes contenues dans iterable
[Link](sep) : renvoie une liste des mots de la chaîne, en utilisant sep comme séparateur de mots. Si sep n'est pas donné, le séparateur utilisé
est l'espace
[Link](old, new) : renvoie une copie de la chaîne dont toutes les occurrences de la sous-chaîne old sont remplacés par new.
etc.

In [21]: s='ceci est un titre'


print([Link]()) # renvoie une nouvelle chaine
print(s) # str est non mutable, s n'a donc pas été modifiée

Ceci est un titre


ceci est un titre

In [24]:
print([Link]("est"))

In [25]: " ".join(["knights", "who", "say", "ni"])

Out [25]: 'knights who say ni'

In [27]:
"--".join(["knights", "who", "say", "ni"])

Out [27]: 'knights--who--say--ni'

In [28]:
print([Link](' '))

['ceci', 'est', 'un', 'titre']

In [29]:
print([Link]('e'))

['c', 'ci ', 'st un titr', '']

In [30]:
print([Link]())

['ceci', 'est', 'un', 'titre']

Au-delà de cette limite, le contenu n'est pas au programme du CC1


Il peut cependant vous aider pour le projet, c'est pourquoi nous le mettons en ligne.

Tuples (ou n-uplets)

Ils sont similaires aux listes mais il sont non mutables.

Type tuple : séquence non mutable et itérable

En tant que séquences, les tuples autorisent :

t[i] : accès à un élément par son indice


len(t) : longueur
min(t), max(t) : minimum et maximum
elem in t : recherche d'élément
[Link](elem) : position d'élément
[Link](elem) : comptage d'élément
t1 + t2, t * 3 : concaténation et répétition

En tant que séquences immutables, les tuples interdisent :

[Link]('a'), [Link](t2), [Link](i, elem), [Link](), [Link](i), [Link](x), [Link](), t[i] = elem, [Link](), [Link]()...

En tant qu'objets itérables, les tuples peuvent être utilisées dans des boucles for :

In [31]:
trucs = ('machin', 'bidule', 'chose')
for elem in trucs:
print(elem)

machin
bidule
chose

Ils s'utilisent par exemple pour mémoriser les coordonnées d'un point du plan, une fraction...

On les note avec des parenthèses:

In [32]:
couple = (2, 64)
type(couple)

Out [32]: tuple

In [33]:
couple[1]

Out [33]: 64

Il est souvent pratique d'affecter simultanément chacun des éléments d'un tuple à une variable. Par exemple :

In [34]:
fraction = (3, 4)
num, denom = fraction
print(num)
print(denom)

3
4

Les parenthèses sont parfois omises autour des éléments d'un tuple :

In [35]:
fraction = 3, 4 # pas de parenthèses !
num, denom = fraction
print(num)
print(denom)

3
4

On se sert généralement d'un tuple pour renvoyer un résultat composé de plusieurs valeurs dans une fonction :

In [36]:
def produit_fractions(f1, f2):
num1, denom1 = f1
num2, denom2 = f2
return num1 * num2, denom1 * denom2 # c'est un tuple !

In [37]:
frac1 = (1, 3)
frac2 = (5, 2)
produit_fractions(frac1, frac2)

Out [37]: (5, 6)


Fichiers

Il est possible de consulter le contenu d'un fichier texte en Python, et de le modifier. On accède la plupart du temps aux lignes successives d'un fichier
à l'aide d'une boucle for.

Descripteurs de fichiers (type file)

Ouverture d'un fichier : f = open(chemin, mode)

Paramètre chemin (chaîne de caractère) : nom (absolu ou relatif) d'un fichier


Paramètre mode (chaîne de caractère) :
lecture seule : 'r' (par défaut)
écriture (crée / écrase le fichier) : 'w'
ajout (écrit à la fin) : 'a'
autres modes possibles pour fichiers binaires

Fermeture : [Link]()

Lire et écrire dans un fichier

Lecture (mode 'r') :

Tout lire d'un coup (une seule chaîne) : contenu = [Link]()


Attention : charge tout le fichier en mémoire !
Attention : inclut les retours à la ligne

Liste des lignes (liste de chaînes) : lst_lignes = [Link]()


Attention : charge tout le fichier en mémoire !
Attention : inclut les retours à la ligne

Prochaine ligne : ligne = [Link]()


Attention : renvoie une chaîne vide à la fin

Parcours ligne par ligne : for ligne in f: ...

Écriture (modes 'w' et 'a') : [Link](chaine)

Attention : n'inclut pas de retour à la ligne ('\n') automatique !

In [1]:
f = open('[Link]', 'w')
for chaine in ['au', 'revoir', 'tout', 'le', 'monde !']:
[Link](chaine)
[Link]()

In [2]:
f = open('[Link]', 'w')
[Link]("\n".join(['au', 'revoir', 'tout', 'le', 'monde !']))
[Link]()

In [3]: f = open('[Link]', 'a')


[Link]('(signé : Machin)\n')
[Link]()

In [4]: f = open('[Link]', 'r')


for ligne in f:
# strip supprime les espaces avant et après la chaîne
print([Link]())
[Link]()

au
revoir
tout
le
monde !(signé : Machin)

In [8]:
f = open('[Link]')
# Décommentez pour voir :
# for ligne in f:
# print([Link]())
[Link]()

Vous aimerez peut-être aussi