Opendata : en français, on dit données ouvertes. Il s'agit d'un concept : le fait que les données et l'information sont un bien commun à l'humanité et qu'il est important de pouvoir la diffuser et la partager. On trouve désormais des fichiers regroupant des données traitant de tout et de rien très facilement sur le Web.
Quelques critères permettant de qualifier une information OpenData :
Complète
Primaire
Opportune
Accessible
Exploitable
Non-discriminatoire
Non-propriétaire
Libre de droits
Permanente
Gratuite
Nous allons en parler un peu ici. Si vous voulez plus de renseignements après cette activité : article Wikipedia.
Prérequis : Dictionnaires et tableaux, tableaux dynamiques.
OpenData : à la fois mouvement philosophique et politique qui vise à diffuser l'information au plus grand nombre. Grossièrement, la notion possède les mêmes fondements que la liberté de la presse : avec une information libre d'accès, on peut lutter facilement contre :
les manipulations ;
les mensonges ;
les contre-vérités.
Un autre lien évident avec l'informatique ? Le monde du logiciel libre : l'accès au code-source permet savoir exactement ce fait un programme, plutôt que devoir faire confiance à l'éditeur du logiciel.
C'est exactement la même chose avec l'OpenData : si on a accès aux informations brutes, on peut analyser les chiffres plutôt que de faire confiance à l'éditeur de l'article.
Il s'agit normalement de publier de façon légale des informations en permettant aux autres de les lire, de les publier et de les exploiter. Il existe de multiples licences liées à ces publications.
Il existe une autre thématique proche de l'OpenData : la fuite de données. Celle des lanceurs d'alerte qui publient des données non libres. Ils savent qu'ils seront poursuivis et qu'ils risquent gros mais décident d'informer le monde d'une malversation ou plus généralement d'un problème. Ainsi le site Wikileaks a publié des données liées aux renseignements américains. Il ne s'agissait pas d'OpenData ici mais la diffusion de ces informations a clairement modifié le monde et la vision qu'ont les gens de la collecte d'informations.
Avec le Web, la diffusion d'informations est facile. Reste le problème de la fiabilité : publier des données ne veut pas dire que l'information soit réelle ! Le travail des journalistes n'est donc pas fini. Au contraire, il ne fait que commencer et il leur faudra désormais des outils informatiques puissants pour analyser différentes sources et fournir une probabilité de véracité.
Nous retrouvons ici Tim Berners-Lee. Le créateur du Web a défini une échelle dans l'OpenData.
Tim Berners-Lee (2010) - CC BY 2.0 - Paul Charliee — originally posted to Flickr
Rang
Signification
★
Données non filtrées ou non structurées (éventuellement dégradées), mises en ligne avec un format non standard ou sans format du tout
★★
Données structurées (données au format CSV, TSV, XML, ou issues d'un format dont la spécification est connue : PDF, fichier tableur...)
★★★
Données librement exploitables. Juridiquement (Cf. licences) et techniquement (les données ne sont pas lisibles uniquement avec un logiciel propriétaire (EXCEL ou autres)).
★★★★
Données datées, identifiées par des URL (avec date de mise à jour) afin que l'on puisse « pointer » un lien vers elles (et les retrouver éventuellement mises à jour).
★★★★★
Données liées à d'autres données graçe à des données communes, pour les contextualiser et les enrichir
Nous allons (re)voir ce que signifient tous ces termes.
1.1 Données non structurées
Une donnée non structurée est une donnée présente mais qu'un système automatisé aura bien du mal à retrouver.
Exemple
Le Marvel Universe regorge de super-héros emblématiques qui ont marqué plusieurs générations. Iron Man est un génie milliardaire en armure, tandis que Captain America représente l’incarnation du héros patriote. Scarlet Witch, avec ses pouvoirs mystiques, impressionne par sa puissance en tant que maitresse de la magie du Chaos. Spider-Man, le célèbre héros araignée, a été incarné par plusieurs personnages, notamment Peter Parker et Miles Morales, chacun apportant une vision unique du justicier masqué. Depuis des décennies, cet univers ne cesse de s'étendre avec des films, des séries et des comics captivants. Il existe également un grand nombre de sous-univers dans l'Univers, avec par rapport les X-Men. Tornade, l'une des héroïnes de X-Men, est capable de contrôler des éléments, et est une force redoutable au sein de l'équipe. De son côté, Malicia est une mutante puissante, capable d'absorber les pouvoirs et souvenirs d'autrui au simple toucher, ce qui fait d’elle une combattante aussi redoutable que tourmentée
01° Quel est le nom et l'archétype du deuxième héros décrit ? Quel est le nom et l'archétype du troisième héros décrit ? ?
...CORRECTION...
Captain America : héros patriote.
Scarlett Witch : maitresse de la magie du Chaos.
Vous venez d'utiliser un centre de traitement de l'information super performant : votre cerveau.
Pas possible pour un ordinateur. Il existe une branche de la recherche informatique qui traite de cette capacité de donner du sens à un texte brut mais c'est loin d'être facile et rapide.
La meilleur façon pour qu'un ordinateur puisse traiter cela est de lui mâcher le travail : nous allons structurer les données.
1.2 Données structurées
Définition et exemple
Une donnée structurée est une donnée présentée selon un format connu et fixe. Plusieurs données du même type partagent la même structure descriptive.
Il peut s'agir par exemple d'un tableau à deux entrées.
Exemple
Identifiant
Nom
Archétype
1er Apparition
0
Iron Man
Génie milliardaire en armure
1963
1
Captain America
Héros patriote
1940
2
Scarlet Witch
Maîtresse de la magie du chaos
1964
3
Spider Man
Justicier masqué
1963
4
Spider Man
Justicier masqué
1963
5
Tornade
Mutante capable de contrôler les éléments
1975
6
Malicia / Rogue
Mutante capable d'absorber les pouvoirs
1981
Vocabulaire
Collection
Attributs
Identifiant (0)
Nom (1)
Archétype (2)
Date d'apparition (3)
Enregistrements
0
Iron Man
Génie milliardaire en armure
1963
1
Captain America
Héros patriote
1940
2
Scarlet Witch
Maîtresse de la magie du chaos
1964
3
Spider Man
Justicier masqué
1963
4
Spider Man
Justicier masqué
1963
5
Tornade
Mutante capable de contrôler les éléments
1975
6
Malicia / Rogue
Mutante capable d'absorber les pouvoirs
1981
Les colonnes sont nommées descripteurs, attributs ou caractères selon les spécialités scientifiques.
Ici, on utilisera souvent attribut.
Toutes les données présentes dans ce tableau partagent les mêmes attributs et les fournissent dans le même ordre : ID - Nom - Archétye - Date d'apparition.
Chaque ligne se nomme enregistrement, objet, ou individu selon la spécialité scientifique.
Ici, on utilisera souvent enregistrement.
La toute première ligne (d'indice 0), en bleu foncé n'est pas un enregistrement. Il s'agit de l'en-tête (header en anglais). Elle permet de connaître le nom des attributs.
L'ensemble des données se nomme la collection ou la tableen informatique (ou population ou relation en mathématique).
Une case (intersection d'un enregistrement et d'un attribut) peut porter le nom de champ.
Le contenu d'une case se nomme une valeur.
Résumé du vocabulaire
L'ensemble des données ➡ Collection
Une colonne ➡ Attribut
Une ligne ➡ Enregistrement
Une case ➡ Champ
Valeur d'une case ➡ Valeur
La toute première ligne ➡ En-tête
02° Quels sont les attributs de la collection précédente ? Combien y-a-t-il d'enregistrements dans cette collection ? Quelle est la valeur qui correspond à l'attribut d'indice 1 et à l'enregistrement d'indice 5 ?
...CORRECTION...
Il y a 4 attributs :
Indice 0 : Identifiant
Indice 1 : Nom
Indice 2 : Archétype
Indice 3 : Date d'apparition
Il y a 7 enregistrements d'indice 0 à 6.
La valeur d'indice 1 en attribut (colonne Nom) et d'indice 5 en enregistrement correspond à Tornade.
03° Quel est le seul attribut qui permette de distinguer les enregistrements des deux incarnations de Spider Man ?
...CORRECTION...
Il s'agit de l'identifiant. On rajoute TOUJOURS un identifiant qu'on définit soi-même. De cette façon, nous sommes certains de pouvoir distinguer deux enregistrements même si les contenus sont similaires.
✎ 04° Peut-on séparer deux individus uniquement à l'aide du nom et du prénom ? A quoi sert le numéro de sécurité sociale ?
...CORRECTION...
Nom et prénom ne sont pas suffisants. Deux personnes peuvent se nommer exactement pareil.
C'est pour cela qu'un adulte dispose de son numéro de sécurité social : il lui est unique (enfn, s'il n'a pas d'enfant de moins de 15 ans).
Nous allons créer des tableaux de tableaux ou des tableaux de dictionnaires.
Vous allez voir que c'est finalement assez intuitif.
Création d'enregistrements
Comme les données sont structurées, nous pourrions stocker les valeurs d'un enregistrement dans un tableau.
1
2
3
enr0=['0','Iron Man','Génie milliardaire en armure','1963']enr1=['1','Captain America','Héros patriote','1940']enr2=['2','Scarlet Witch','Maîtresse de la magie du chaos','1964']
05° Que va-t-on récupérer si on lance ceci dans la console Python après avoir placé les 3 variables précédentes en mémoire ?
On récupère donc bien les valeurs stockées dans l'attribut TYPE qui correspond à l'index 1.
✎ 06° Que doit-on taper pour récupérer l'archétype de l'enregistrement 2 ?
Pour l'instant, nous avons encore 3 variables : une pour chaque enregistrement. C'est pénible.
Création de la collection
Nous allons stocker nos enregistrements-tableau dans un tableau. On obtient ainsi un tableau de tableaux.
1
2
3
4
5
enr0=['0','Iron Man','Génie milliardaire en armure','1963']enr1=['1','Captain America','Héros patriote','1940']enr2=['2','Scarlet Witch','Maîtresse de la magie du chaos','1964']maCollec=[enr0,enr1,enr2]
07° Que va-t-on récupérer si on lance ceci dans la console Python après avoir placé les 4 variables précédentes en mémoire ?
>>> maCollec[0]
>>> maCollec[1]
>>> maCollec[2]
...CORRECTION...
>>> maCollec[0]
['0', 'Iron Man', 'Génie milliardaire en armure', '1963']>>> maCollec[1]
['1', 'Captain America', 'Héros patriote', '1940']>>> maCollec[2]
['2', 'Scarlet Witch', 'Maîtresse de la magie du chaos', '1964']
Un élément maCollec[i] du tableau maCollec est donc un tableau. Et si on veut lire uniquement un attribut ? Il suffit de rajouter un crochet supplémentaire derrière [i].
Traduction en Français : maCollec[0][1] veut dire "va chercher l'élément d'indice 0 du tableau maCollec. Dans le tableau que tu récupères, va maintenant chercher l'élement d'indice 1.
✎ 08° Sur le même principe que l'exemple précédente, que va répondre l'interpréteur Python à l'instruction suivante ?
>>> maCollec[1][3]
Pour se passer des variables intermédiaires, nous allons taper ceci :
1
2
3
4
5
maCollec=[['0','Iron Man','Génie milliardaire en armure','1963'],['1','Captain America','Héros patriote','1940'],['2','Scarlet Witch','Maîtresse de la magie du chaos','1964']]
On ouvre un tableau et on y place des tableaux séparés par des virgules.
On pourrait créer ce tableau d'une nouvelle façon : par extension et ajouts successifs, en rajoutant au fur et à mesure les nouveaux enregistrements avec la méthode append() (to append se traduit par le verbe rajouter).
1
2
3
4
maCollec=[]maCollec.append(['0','Iron Man','Génie milliardaire en armure','1963'])maCollec.append(['1','Captain America','Héros patriote','1940'])maCollec.append(['2','Scarlet Witch','Maîtresse de la magie du chaos','1964'])
✎ 09° Utiliser ce programme. Demander dans la console le contenu de maCollec. Donner l'instruction permettant de rajouter un enregistrement de votre choix. Fournir le code à rajouter dans le programme et le résultat de la variable maCollec après modification.
Dernière question de cette sous-partie : voyons comment visualiser le contenu de notre collection proprement en utilisant les fStrings et leurs capacités à forcer l'affichage sur un nombre précis de caractères (20 ici).
✎ 10° Utiliser ce programme qui mémorise une collection et une fonction visualiser(). Taper ensuite visualiser(maCollec) dans la console pour voir le contenu de la collection d'enregistrements.
1
2
3
4
5
6
7
8
9
10
defvisualiser(c:'list[list]')-> None:"""affiche le contenu des enregistements e de la collection c"""foreinc:print(f"{e[1]:20}{e[2]:35}{e[3]:20}")maCollec=[]maCollec.append(['0','Iron Man','Génie milliardaire en armure','1963'])maCollec.append(['1','Captain America','Heros patriote','1940'])maCollec.append(['2','Scarlet Witch','Maîtresse de la magie du chaos','1964'])
Questions
Rajouter l'appel à la fonction en fin de programme ou faire l'appel dans la console.
Justifier qu'on puisse ici se passer de l'utilisation d'une boucle avec indice sur la ligne 4 (for e in c plutôt que for i in range(len(c))).
Fournir le code de la même fonction mais en utilisant plutôt les indices.
...CORRECTION...
>>> visualiser(maCollec)
Iron Man Génie milliardaire en armure 1963
Captain America Heros patriote 1940
Scarlet Witch Maîtresse de la magie du chaos 1964
On peut se passer des indices puisqu'on ne modifie pas les tableaux.
Pour le parcours par indices, voilà ce que cela pourrait donner :
1
2
3
4
5
6
7
8
9
10
11
12
13
defvisualiser(c:'list[list]')-> None:"""affiche le contenu des enregistements e de la collection c"""foriinrange(len(c)):e = c[i]
print(f"{e[1]:20}{e[2]:35}{e[3]:20}")maCollec=[]maCollec.append(['0','Iron Man','Génie milliardaire en armure','1963'])maCollec.append(['1','Captain America','Heros patriote','1940'])maCollec.append(['2','Scarlet Witch','Maîtresse de la magie du chaos','1964'])visualiser(maCollec)
Nous n'allons pas taper directement le contenu des tableaux, surtout s'il y a 30 millions de lignes. Dans l'une des activités Python, nous verrons comment récupérer les données directement depuis un fichier texte un peu particulier qu'on nomme fichier CSV.
Le problème du tableau de tableaux, c'est que normalement toutes les "cases" doivent contenir le même type d'éléments (que des integers, que des strings ...)
En Python, nous n'utilisons pas réellement des tableaux mais des objets de type list qui permettent d'avoir des types différents dans les cases. Mais, sinon, comment faire ?
Et bien, on pourrait utiliser un tableau de tuples.
Lors de la déclaration, la seule différence vient de la présence de parenthèses lorsqu'on fournit les enregistrements.
1
2
3
4
5
maCollec=[('0','Iron Man','Génie milliardaire en armure',1963),('1','Captain America','Héros patriote',1940),('2','Scarlet Witch','Maîtresse de la magie du chaos',1964)]
Deux intérêts à cette façon de faire :
On peut maintenant mettre ce qu'on veut dans les éléments, ils n'ont plus à être de même type (comme les dates qui sont maintenant des integers).
Les tuples de Python sont immuables : on ne pourra pas modifier involontairement les enregistrements.
Le problème du tableau de tableaux ou du tableau de tuples, c'est qu'il faut connaitre le numéro d'indice de l'attribut pour le trouver. C'est un peu pénible.
On peut faire mieux avec les dictionnaires : il suffit de créer un tableau de dictionnaires dont la clé est ... le nom du descripteur (ou attribut) !
1
2
3
4
5
enr={}enr['id']=0enr['nom']='Iron Man'enr['archétype']='Génie milliardaire en armure'enr["date d'apparition"]=1963
Une fois enr en mémoire, on peut alors lancer ceci dans la console :
>>> enr["Date d'apparition"]
1963
Avantages : on voit le nom de l'attribut et on peut mettre le type qu'on désire tant pour la clé que pour la valeur. Plus de risque de se tromper de numéro de colonnes.
Désavantage : il faudrait tout refaire alors que le tableau est déjà créé !
Nous allons donc automatiser les choses en créant une fonction creer_enregistrement() qui attend un tableau en paramètes et qui renvoie le dictionnaire correspondant.
✎ 11° Utiliser ce programme qui utilise la fonction creer() pour créer et renvoyer un dictionnaire créé à partir du tableau val des 4 valeurs transmises lors de l'appel.
Voici son prototype :
defcreer(val:list) -> dict
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
defcreer(val):"""Renvoie un dictionnaire ayant les clés id, nom, archétype et date d'apparition :: param val(list) :: un enregistrement de super-héros :: return (dict) :: un dictionnaire-enregistrement avec les bonnes clés .. exemple .. >>> creer([0, 'Iron Man', 'Génie milliardaire en armure', 1963]) {'id': 0, 'nom': 'Iron Man', 'archétype': 'Génie milliardaire en armure', "Date d'apparition": 1963} """d={}d['id']=val[0]d['nom']=val[1]d['archétype']=val[2]returndenr=creer([0,'Iron Man','Génie milliardaire en armure',1963])print(enr)
Question
Expliquer pourquoi la fonction ne renvoie pas exactement le dictionnaire attendu par rapport à la documentation :
>>> creer([0, 'Iron Man', 'Génie milliardaire en armure', 1963])
{'id': 0, 'type': 'Iron Man', 'utilisation': 'Génie milliardaire en armure'}
...CORRECTION...
Aucune demande pour créer la clé correspondant à la date dans le code.
✎ 12° Rajouter la ligne permettant de gérer la clé "date d'apparition" dans la fonction creer().
...CORRECTION...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
defcreer(val):"""Renvoie un dictionnaire ayant les clés id, nom, archétype et date d'apparition :: param val(list) :: un enregistrement de super-héros :: return (dict) :: un dictionnaire-enregistrement avec les bonnes clés .. exemple .. >>> creer([0, 'Iron Man', 'Génie milliardaire en armure', 1963]) {'id': 0, 'nom': 'Iron Man', 'archétype': 'Génie milliardaire en armure', "Date d'apparition": 1963} """d={}d['id']=val[0]d['nom']=val[1]d['archétype']=val[2]d["date d'apparition"]=val[3]returndenr=creer([0,'Iron Man','Génie milliardaire en armure',1963])print(enr)
Maintenant que nous savons créer nos enregistrements, nous n'avons plus qu'à les rajouter progressivement par extension et ajouts successifs (avec la méthode append()) dans notre collection. Nous allons donc créer un tableau de dictionnaires.
13° Rajouter ces instructions sous votre fonction et afficher ensuite le contenu de la collection maCollec dans la console.
20
21
22
23
24
# ProgrammemaCollec=[]maCollec.append(creer([0,'Iron Man','Génie milliardaire en armure',1963]))maCollec.append(creer([1,'Captain America','Héros patriote',1940]))maCollec.append(creer([2,'Scarlet Witch','Maîtresse de la magie du chaos',1964]))
On rappelle que la structure d'un programme est la suivante
Les importations
Les déclarations de CONSTANTES
Les définitions de fonctions
Les instructions du programme principal
Vous obtenez donc un tableau de dictionnaires ayant tous les mêmes clés.
Nous aurions obtenu le même résultat si nous avions tapé ceci à la main :
1
2
3
4
5
maCollec=[{'id':0,'nom':'Iron Man','archétype':'Génie milliardaire en armure',"date d'apparition":1963},{'id':1,'nom':'Captain America','archetype':'Héros patriote',"date d'apparition":1940},{'id':2,'nom':'Scarlet Witch','archetype':'Maîtresse de la magie du chaos',"date d'apparition":1964}]
Les clés des dictionnaires sont les attributs de notre collection.
Chacun des dictionnaires est l'un des enregistrements.
Comme les dictionnaires ont tous les mêmes clés, on dira que ce sont des p-uplets nommés (4-uplets nommés ici) : des séquences de 4 éléments ayant chacun un nom bien particulier.
14-A° Que va-t-on obtenir en tapant ceci dans la console :
>>> maCollec[2]
...CORRECTION...
On obtient l'indice 2 de notre tableau-collection, à savoir un dictionnaire.
{'id': 2, 'nom': 'Scarlet Witch', 'archétype': 'Maîtresse de la magie du chaos', "date d'apparition": 1964}
14-B° Que va-t-on obtenir en tapant ceci dans la console :
>>> maCollec[0]['nom']
...CORRECTION...
Avec maCollec[1], on obtient l'indice 0 de notre tableau, à savoir un dictionnaire.
Vous avez vu en SNT qu'il existe des formats courants de données. Cela permet de créer des données et de les distribuer dans un format qui sera facilement utilisable par quelqu'un d'autre.
On pourra croire qu'on peut simplement créer des fichiers Python avec des tableaux de tableaux ou des tableaux de dictionnaires, mais comment faire si quelqu'un veut récupérer vos données avec un autre langage que Python ?
L'un des formats les plus répandus est le format CSV.
5 Fichier CSV
Description générale
C'est un moyen simple de transmettre des données : c'est un simple fichier-texte compréhensible par n'importe quel langage de programmation et n'importe quel tableur.
CSV veut dire Comma Separated Values : des valeurs séparées par des virgules.
Un tableur est capable d'ouvrir les fichiers CSV.
Structure des données dans le fichier CSV
(option) La première ligne du fichier contient les intitulés des attributs : l'en-tête.
Chaque ligne constitue un enregistement. Rappel : la fin de ligne correspond à un octet valant 10 (norme ASCII), représentée ci-dessous par ↲, et par le string "\n" en Python.
Chaque valeur est séparée des autres valeurs de l'enregistrement par une virgule.
Exemple
A titre d'exemple voici la représentation CSV d'un tableau contenant la collection ci-dessous :
Cette partie ne traite que de la gestion des données d'un futur jeu Pyxel de type "Space Invaders" que vous allez réaliser dans l'activité Créer un Programme 3 de la partie Python.
Quelques informations générales sur les données du jeu
Nous allons stocker les données du jeu dans plusieurs variables globales qui sont ou contiennent des dictionnaires. Les clés courantes sont :
'x' et 'y' pour les coordonnées de l'objet;
'c' pour la couleur que devra avoir l'objet à l'écran. Un entier entre 0 et 15.
'pv' pour le nombre de points de vie de l'objet.
Voici les variables globales :
vaisseau : un dictionnaire contenant des informations sur le vaisseau du joueur : ses coordonnées x et y, les points gagnés, sa couleur et son état (True si actif, False si inactif). Exemple :
vaisseau = {'x':50, 'y':100, "points":0, 'c':2}
ennemis : une table sous forme d'un tableau de dictionnaires (list[dict]), contenant les ennemis, un dictionnaire par ennemi sous forme d'un dictionnaire par ennemi. Exemple ici avec 3 ennemis :
tirs : une table sous forme d'un tableau de dictionnaires, contenant les tirs actuellement à l'écran, un dictionnaire par tir. Exemple avec deux tirs :
explosions : une table sous forme d'un tableau de dictionnaires, contenant les explosions actuellement à l'écran, un dictionnaire par tir. Exemple avec une explosion :
Notez bien que ce n'est pas une affectation sur le dictionnaire : l'affectation est faite sur l'un des contenus des associations clé-valeur du dictionnaire, pas sur le dictionnaire lui-même.
Accès en modification (dict) : coût CONSTANT par rapport au nombre n d'éléments.
Rajout d'un nouveau couple
On peut rajouter de la même façon un couple qui n'existe pas encore.
Imaginons un nouvel élève nommé David qui a eu 15.
⚙ 16° Dans notre programme, un ennemi sera un vaisseau alien ennemi. Nous allons vouloir stocker ses données dans un dictionnaire, le type dict de Python.
La clé 'x' fera référence à son abscisse, sa colonne à l'écran;
La clé 'y' fera référence à son ordonnée, sa ligne à l'écran;
La clé 'pv' fera référence à ses points de vie : 0 pour un ennemi détruit, positif sinon;
La clé 'c' fera référence à son couleur, un nombre compris entre 1 et 15 dans Pyxel.
>>> ennemi = {'x':100, 'y':30, 'pv':2, 'c':6}
Questions
Comment récupérer dans une variable x la valeur associée à la clé 'x' ?
Comment incrémenter la valeur associée à la clé 'x' ?
⚙ 17° Dans notre programme, il y aura plusieurs ennemis. Nous allons les stocker dans un tableau ennemis.
Compléter le programme ci-dessous pour qu'on parvienne à afficher la couleur de tous les ennemis qui ont une ordonnée y supérieure à 85.
1
2
3
4
5
6
7
8
9
10
11
ennemis=[{'x':100,'y':50,'c':3,'pv':2},{'x':120,'y':80,'c':5,'pv':2},{'x':80,'y':110,'c':8,'pv':2},{'x':50,'y':90,'c':2,'pv':2},{'x':40,'y':20,'c':14,'pv':2},]forennemiinennemis:# Pour chaque ennemi du tableau ennemisif...:# si cet ennemi a une ordonnée y supérieure à 80 print(...)# affiche sa couleur
Sur l'exemple donné, le programme doit donc afficher 8 et 2.
...CORRECTION...
1
2
3
4
5
6
7
8
9
10
11
ennemis=[{'x':100,'y':50,'c':3,'pv':2},{'x':120,'y':80,'c':5,'pv':2},{'x':80,'y':110,'c':8,'pv':2},{'x':50,'y':90,'c':2,'pv':2},{'x':40,'y':20,'c':14,'pv':2},]forennemiinennemis: # Pour chaque ennemi du tableau ennemisifennemi['y']>80:# si cet ennemi a une ordonnée supérieure à 80 print(ennemi['c'])# affiche sa couleur
2/3 Rajouter un ennemi
⚙ 18° Nous allons vouloir faire apparaître régulièrement des ennemis à l'écran. Pour cela, il va falloir les rajouter dans le tableau ennemis (de type list en Python) ennemis avec un s.
Question : quelle solution du QCM permet effectivement de rajouter l'ennemi dans le tableau ennemis ? Critiquer les solutions non retenues.
Erreur d'exécution : on tente de concaténer un type list et un type dict. Cela n'est pas autorisé car ca ne veut rien dire.
ennemis=ennemis+ [ennemi]
L'instruction fonctionne mais crée un nouveau tableau plutôt que de modifier le tableau en place. On concaténe un tableau avec un tableau qui ne contient qu'une seule case.
ennemis.append(ennemi)
C'est la bonne solution : on agit sur le tableau ennemis en lui ajoutant une case à la fin.
ennemi.append(ennemis)
C'est faux : ennemi sans s est un dictionnaire.Ici, on demande de modifier le dictionnaire en lui 'ajoutant' le tableau des ennemis. Cela provoque une erreur d'exécution car le type dict ne dipose pas de cette méthode append().
3/3 Supprimer un ennemi
⚙ 19-A° Reste à voir comment faire disparaître les ennemis qui sortent de l'écran par exemple. Pour cela, il va falloir les supprimer du tableau ennemis à l'aide de la méthode remove(x).
Compléter le programme pour qu'il permette de supprimer du tableau les ennemis dans l'ordonnée y est supérieur à 85 par exemple.
Lancer pour vérifier : vous devriez constaté que vous n'avez pas supprimé tous les ennemis mais un seul... Nous verrons comment faire mieux dans la question 19-B.
1
2
3
4
5
6
7
8
9
10
11
12
13
ennemis=[{'x':100,'y':50,'c':3,'pv':2},{'x':120,'y':80,'c':5,'pv':2},{'x':80,'y':110,'c':8,'pv':2},{'x':50,'y':90,'c':2,'pv':2},{'x':40,'y':20,'c':14,'pv':2},]forennemiinennemis:# Pour chaque ennemi du tableau ennemisif ...:# si cet ennemi a une ordonnée supérieure à 85
... # Supprime l'ennemi du tableau des ennemisprint(ennemis)
...CORRECTION...
1
2
3
4
5
6
7
8
9
10
11
12
13
ennemis=[{'x':100,'y':50,'c':3,'pv':2},{'x':120,'y':80,'c':5,'pv':2},{'x':80,'y':110,'c':8,'pv':2},{'x':50,'y':90,'c':2,'pv':2},{'x':40,'y':20,'c':14,'pv':2},]forennemiinennemis:# Pour chaque ennemi du tableau ennemisifennemi['y'] >85:# si cet ennemi a une ordonnée supérieure à 85 ennemis.remove(ennemi) # Supprime l'ennemi du tableau des ennemisprint(ennemis)
Vous devriez constater qu'on ne supprime que l'ennemi dont l'ordonnée est 110. Pas le 90... Bizarre, non ?
⚙ 19-B° Le code précédent ne fait pas ce qu'on désire tout simplement à cause du principe des tableaux : lorsque vous supprimez une case, Python va décaler le contenu des cases de droite pour remplir la case devenue vide.
Ainsi, imaginons le tableau des ennemis suivants (je ne représente que l'ordonnée dans les cases) et la situation, lorsqu'on tombe sur le 110 :
X X Ici
ennemis = [ {50}, {80}, {110}, {90}, {20} ]
Puisqu'on demande de le supprimer, voici ce que devient le tableau temporairement :
X X Ici
ennemis = [ {50}, {80}, {90}, {20} ]
Et c'est maintenant que le problème arrive : nous avons fini de traiter cette case rouge de son point de vue : il passe donc à la case suivante :
X X X Ici
ennemis = [ {50}, {80}, {90}, {20} ]
Et donc, Python zappe le 90 en passant à la case suivante...
Utiliser ce nouveau programme qui itére sur une copie de tableau initial (créée avec list(ennemis)) et pas directement sur le tableau.
1
2
3
4
5
6
7
8
9
10
11
12
13
ennemis=[{'x':100,'y':50,'c':3,'pv':2},{'x':120,'y':80,'c':5,'pv':2},{'x':80,'y':110,'c':8,'pv':2},{'x':50,'y':90,'c':2,'pv':2},{'x':40,'y':20,'c':14,'pv':2},]forennemiinlist(ennemis):# Pour chaque ennemi initialement dans le tableau ennemisifennemi['y'] >85:# si cet ennemi a une ordonnée supérieure à 85 ennemis.remove(ennemi) # Supprime l'ennemi du tableau des ennemisprint(ennemis)
...CORRECTION...
Vous devriez constater qu'on supprime bien tous les ennemis qui vont trop loin maintenant.
✔ 20° Dernier point, plus informatif qu'autre chose : on ne peut pas modifier un tableau qu'on est en train de lire par indices : en supprimant cette case, on réduit de 1 le nombre d'indices disponibles et on finira par aller en dehors des indices autorisés. Il faut donc nécessairement utiliser le parcours par valeurs.
Tester le programme ci-dessous pour vérifier qu'il NE fonctionne PAS alors qu'il est plutôt similaire à celui de la question 19 si ce n'est qu'on passe par un parcours par indices.
1
2
3
4
5
6
7
8
9
10
11
ennemis=[{'x':100,'y':50,'c':3,'pv':2},{'x':120,'y':80,'c':5,'pv':2},{'x':80,'y':110,'c':8,'pv':2},{'x':50,'y':90,'c':2,'pv':2},{'x':40,'y':20,'c':14,'pv':2},]foriinrange(len(ennemis)): # Pour chaque indice du tableau ennemisifennemis[i]['y'] >85:# si cet ennemi a une ordonnée supérieure à 85 ennemis.remove(ennemis[i]) # Supprime l'ennemi du tableau des ennemis