Aller au contenu

T2.1 Compléments sur les listes⚓︎

2.1.9 Copie de listes⚓︎

Vu en classe : une copie un peu trop parfaite

Observez le code ci-dessous, réalisé sans trucage.

>>> listA = [1, 2, 3]
>>> listB = listA
>>> listA.append(7)
>>> listB
[1, 2, 3, 7]
>>> listB.append(8)
>>> listA
[1, 2, 3, 7, 8]

Tout se passe comme si les listes listA etlistB étaient devenus des clones «synchronisés» depuis l'affectation listB = listA.

Analyse grâce à PythonTutor

L'illustration de PythonTutor nous donne la clé de l'énigme : image

listA etlistB sont en fait un seul et même objet.

Comment en avoir le cœur net ? En observant leur adresse-mémoire, disponible grâce à la fonction id :

>>> id(listA)
140485841327616
>>> id(listB)
140485841327616

Ceci met en évidence que la métaphore du tiroir dont on se sert pour expliquer ce qu'est une variable est malheureusement inexacte. Une variable est une référence vers une adresse-mémoire. Si deux variables font référence à la même adresse-mémoire, alors elles sont totalement identiques: toute modification de l'une entraîne une modification de l'autre.

Mais alors, comment copier le contenu d'une liste vers une autre sans créer un clone ?⚓︎

Deux façons (entre autres) de créer une vraie copie d'une liste

>>> listA = [3, 4, 5]
>>> listB = listA.copy()
>>> listC = list(listA)

Exercice 1

Contrôler les adresses mémoires avec la fonction id pour prouver que les exemples précédents produisent bien des objets différents.

2.1.10 Listes en compréhension⚓︎

Des exemples simples⚓︎

On a déjà vu comment créer une liste par extension, c'est-à-dire en explicitant tous ses éléments:

tab = [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

Ou bien par ajouts successifs à l'aide d'une boucle for, ce qui est est bien plus efficace, surtout lorsque la taille du tableau est grande:

1
2
3
tab = []
for k in range(10):
    tab.append(k**2)

Python permet également de combiner ces deux écritures, en «rentrant» la boucle for dans les crochets de définition de la liste:

tab = [k**2 for k in range(10)]

On dit qu'on a créé la liste en compréhension:

  • tab est constituée des carrés de k pour k allant de 0 à 9;
  • ou bien encore tab est la liste des carrés des entiers allant de 0 à 9.

On peut également créer une liste en compréhension en parcourant les éléments d'un iterable déjà existant, au lieu d'un range. Créons par exemple la liste des images par une fonction f calculées sur une liste d'antécédents:

1
2
3
4
5
6
antecedents = [-1, 0, 5, 10, 100]

def f(x):
    return 2*x + 3

images = [f(x) for x in antecedents]

Avec un filtre⚓︎

Reprenons par exemple l'exercice 4 du cours sur les listes. On souhaitait garder les valeurs positives de la liste temp:

1
temp = [11, 28, -16, -18, -10, 16, 10, 16, 2, 7, 23, 22, -4, -2, 19, 16, 22, -8, 18, -14, 29, -1, 16, 22, -5, 6, 2, -4, 9, -17, -13, 22, 14, 24, 22, -9, -18, -9, 25, -11, 17, 17, 25, -10, 2, -18, 29, 14, -16, 7]
La solution retenue:
1
2
3
4
temp_pos = []
for t in temp:
    if t >= 0:
        temp_pos.append(t)

On peut créer la même chose en compréhension, en incluant l'instruction conditionnelle if dans la définition de la liste:

1
temp_pos = [t for t in temp if t >= 0]

En deux dimensions⚓︎

On peut se servir de cette méthode pour construire rapidement des tableaux à deux dimensions. Par exemple, voici comment on peut créer un tableau de zéros de 3 lignes et 5 colonnes:

tab = [5 * [0] for i in range(3)]

2.1.11 Exercices⚓︎

Dans chaque exercice, la liste doit être crée en compréhension.

Exercice 1

Dans chaque cas, écrire la liste produite par l'instruction donnée:

  1. [3*i for i in range(1, 6)]
  2. [k**2 + 1 for k in range(5)]
  3. [k**3 for k in range(20) if k%5 == 0]
  4. [2*m for m in ['bla', 'to', 'pa', 'tut']
  5. [n+5 for n in [7, 17, 9, 5, 8, 18, 15]]
  6. [k for k in [3, -1, 7, 0, 8, -5, 23, 12, -42, 1001, 78, -98, 72, 50] if k%7 == 0]

Il suffit d'exécuter dans une console python...

Exercice 2

Construire chacune des listes suivantes en compréhension:

  1. la liste des doubles des éléments de [-4, 0, 7, -12, 42, 78]
  2. la liste des doubles des éléments de [-4, 0, 7, -12, 42, 78] qui sont strictement positifs.
  3. les éléments de la première «colonne» d'un tableau tab à deux dimensions.
  1. On écrit [2*n for n in [-4, 0, 7, -12, 42, 78]] .
  2. On ajoute un filtre à la liste précédente: [2*n for n in [-4, 0, 7, -12, 42, 78] if n > 0] .
  3. On sélectionne uniquement les éléments d'indice 0 dans chaque élément (de type list) de tab:

    1
    [ligne[0] for ligne in tab]
    

Exercice 3

Créer la liste constituée des valeurs absolues des entiers contenus dans la liste valeurs.

valeurs = [-2, 5, 1, -9, 2, 12, -8, -15, 7, 14, -27, 0, -2, 4, -5]
1
2
valeurs = [-2, 5, 1, -9, 2, 12, -8, -15, 7, 14, -27, 0, -2, 4, -5]
absolues = [abs(v) for v in valeurs]

Exercice 4

Créer la liste contenant tous les entiers inférieurs ou égaux à 100 multiples de 7.

1
lst = [k for k in range(101) if k%7 == 0]

Exercice 5

Reprende le pydéfi Le jardin des Hespérides en écrivant en compréhension la liste des nombres à sommer.

1
pommes = [etage ** 2 for etage in range(51) if etage%3 == 0]

Exercice 6

On considère la liste suivante:

lst = [51, 52, 66, 91, 92, 82, 65, 53, 86, 42, 79, 95]
Seuls les nombres entre 65 et 90 ont une signification : ce sont des codes Unicode de lettres (récupérables par la fonction chr).

Créer une liste sol qui contient les lettres correspondants aux nombres ayant une signification.

1
sol = [chr(code) for code in lst if code >= 65 and code <= 90]

Exercice 7

Consulter l'énoncé du pydéfi Le lion de Némée .

  1. Écrire une fonction prenant en paramètre une lettre et qui renvoie sa «valeur». Pour rappel:

    >>> ord('A')
    65
    

  2. Écrire une fonction prenant en paramètre une chaîne de caractères et qui renvoie sa «valeur». Vous devez créer une liste en compréhension utilisant la fonction de la question 1, et l'utilisation de la fonction sum est autorisée.

  3. Créer en compréhension la liste des valeurs des divinités.

Pour la fonction split utilisée ci-dessous, voir sur cette page .

1
divinites = 'ARTEMIS ASCLEPIOS ATHENA ATLAS CHARON CHIRON CRONOS DEMETER EOS ERIS EROS GAIA HADES HECATE HEPHAISTOS HERA HERMES HESTIA HYGIE LETO MAIA METIS MNEMOSYNE NYX OCEANOS OURANOS PAN PERSEPHONE POSEIDON RHADAMANTHE SELENE THEMIS THETIS TRITON ZEUS'.split()
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
divinites = 'ARTEMIS ASCLEPIOS ATHENA ATLAS CHARON CHIRON CRONOS DEMETER EOS ERIS EROS GAIA HADES HECATE HEPHAISTOS HERA HERMES HESTIA HYGIE LETO MAIA METIS MNEMOSYNE NYX OCEANOS OURANOS PAN PERSEPHONE POSEIDON RHADAMANTHE SELENE THEMIS THETIS TRITON ZEUS'.split()

def valeur(lettre: str) -> int:
    '''
    Renvoie la valeur d'une lettre capitale de l'alphabet.
    Par ex: A -> 1, B -> 2, ... Z -> 26
    '''
    return ord(lettre) - 64

def valeur_mot(mot: str) -> int:
    '''
    Renvoie la valeur d'un mot étant la somme des valeurs des lettres le 
    constituant.
    '''
    valeurs_lettres = [valeur(l) for l in mot]
    return sum(valeurs_lettres)

valeurs_divinites = [valeur_mot(d) for d in divinites]