3.5. Représentation des données#
Objectifs
- Ce cours poursuit 2 objectifs:
Vous rappeler les types de données de base en Python ainsi que les instructions pour les manipuler.
Vous permettre de concevoir des structures de données élaborées pour modéliser les informations nécessaires à la réalisation de votre projet.
- Objectif 3:
manipuler les types de base python
représenter, initialiser et modifier des données complexes (grilles, arbres et graphes)
- Validation:
Pour valider cet objectifs, vous devrez être capable de construire, représenter et modifier des données complexes. Une donnée complexe peut par exemple être un dictionnaire contenant une chaîne de caractères et une liste de liste de tuples de 3 entiers. Pour manipuler une telle donnée vous devrez comprendre si elle forme un arbre ou un graphe et pouvoir enchaîner une suite d’opérateur d’indexation :
data['map'][2][1]=(2,1,5)
.
3.5.1. Les types de bases#
3.5.1.1. Résumé#
Une donnée informatique est une suite de 1 et 0 plus ou moins grande dans la mémoire de la machine. Lorsqu’on connaît le type d’une donnée, il devient possible de décoder cette suite de bits pour lui donner une signification et donc de l’utiliser.
Lorsque nous écrivons un programme, nous manipulons les données en les affectant à des variables. En python, le typage d’une variable est automatique et dynamique puisqu’il correspond au type de la dernière donnée affectée à cette variable. Nous n’avons donc moins besoin de nous soucier du typage des variables que dans d’autre langage. Nous devons néanmoins maîtriser le type des données pour les manipuler correctement.
Le tableau suivant récapitule les types de bases que vous avez déjà abordés en cours d’algorithmique. La dernière colonne indique si le type correspond à une donnée mutable ou non, ce qui a un impacts important sur le comportement d’un programme lorsqu’on passe les données en paramètre d’une fonction (voir portée et passage).
Types
Exemples
Mots clés
Modifiable
Booléen:
a= False
bool
non
Entier:
b=-12
int
non
Réel:
c=-1.2
oud=3.5e-9
float
non
Chaîne:
e="toto"
» ouf='toto'
str
non
N-uplet:
(g=12, "toto")
tuple
non
Liste:
h=[1,2,3]
list
oui
Dictionnaire:
i={'a':4,'r':8}
dict
oui
Object
o=object()
object
oui
Vous pouvez vous référer au cours de S1 pour retrouver les informations concernant ces types, notamment pour les booléens, les entiers et les réels. Nous revenons ici sur les types : str
, tuple
, list
et dict
. La page de documentation de Python sur les Built-in Types
vous fournira de nombreux éléments pour manipuler ces données.
3.5.1.2. Représentation des variables#
Attention, il vous faut maintenant trouver un papier et un crayon! Nous allons nous entraîner à dessiner des données. Cela va nous aider à comprendre et à concevoir des programmes. Cela permet d’illustrer les notions de références et de données non modifiables très importantes en python.
En effet, en python une variable est une référence vers une donnée.
Le code r = 3
crée ainsi une référence r
vers une donnée de type entier de valeur non modifiable 3
.
Voici comment représenter ces variables.
Représenter un entier :
Représenter un booléen :
Représenter un réel :
Représenter `None` :
La façon de dessiner proposée ici est un « bricolage » //add-hoc// pour ce cours. Une telle représentation graphique permet de se représenter l’état de la mémoire à un certain instant. Pour comprendre ce qu’il se passse dans la mémoire du programme avec les données non modifiables voici un exemple simple ou on dessine l’état de la mémoire après chaque instruction.
Comprendre les la notion de « non modifiable » :
On comprend ici que le caractère non-modifiable des entiers implique qu’on ne modifie jamais la valeur d’un entier mais qu’on en refabrique un autre ailleurs à chaque calcul.
3.5.1.3. Les chaînes de caractères#
Indication
Chaîne de caractères
Une chaîne de caractères est une séquence non modifiable de caractères. On les représente de 2 façons : "my_string"
ou 'my_string'
.
Indication
Quand utiliser une chaîne de caractères?
(Extraits de cahiers des charges)
« …le joueur sera décrit par son score, son nom, sa position… »
« …Lorsqu’on rentre dans une nouvelle pièce, la description de la pièce est affichée sous la carte… »
« …le joueur saisit la réponse au clavier … »
Les chaînes de caractères servent à de nombreuses choses. Il est essentiel de maîtriser leur manipulation. Voici quelques exemples d’opérations qui peuvent être réalisées:
#creation d'une chaîne
s="toto"
#obtenir la taille
print len(s)
#concatenation de chaines
s1 = "Methodes"+" de"
s2 = " developpement"
s3 = s1 + s2
print s3
#acces à un caractere d'une position donnee.
s4="ABcD"
c=s4[2]
print c
#operation interdite, car une chaine est non modifiable:
s4[2] ="C"
#conversion d'une chaine en entier, puis en reel, puis à nouveau chaine de caracteres :
s5 = str(float(int("12")))
À faire
Tester toutes ces instructions sur des chaînes de votre invention
Pour plus d’informations sur la manipulation des chaînes, familiarisez vous avec la documentation de Python. Elle indique l’ensemble des opérations qui peuvent être exécutées sur ce type de données (ici par exemple).
Une chaîne est une séquence de caractères. Nous utiliserons donc les chaînes de caractères pour décrire les données textuelles du jeu. Une chaîne de caractères peut contenir une lettre, un mot, une phrase ou un texte de plusieurs lignes. Elle peut également être vide. Les caractères qui composent la chaîne sont des caractères imprimables ou des caractères de contrôle (tabulation, retour à la ligne…). Basiquement, ces caractères sont codés par des 1 et des 0 (comme toutes les données dans la machine). La table ASCII permet d’établir une correspondance entre le codage binaire du caractère (donné en hexadécimal dans l’exemple) et ce qu’il faut afficher à l’écran:

On peut alors sélectionner un caractères de la table pour l’introduire dans une chaîne de caractères:
#normal
s1 = "ABC"
#octal
s2= "\101BC"
#hexadécimal
s3="\x41BC"
La table ASCII contient tous les caractères pour écrire en anglais. Afin de permettre l’écriture dans d’autres langues, il existe des versions étendues de la table ASCII qui introduisent des lettres accentuées et d’autres caractères spéciaux. L’utilisation de ces extensions a introduit des problèmes de compatibilité d’un pays à l’autre, d’un OS à l’autre, voire d’un logiciel à l’autre. Lorsque que vous lirez des fichiers textes, il peut être utile de connaître le système de codage utilisé. En exécutant le code suivant sur votre machine vous aurez la liste des encodages connu par votre interpréteur Python :
import encodings
for e in sorted(set(encodings.aliases.aliases.values())):
print e
Une norme fait référence pour répertorier les différents caractères utilisés dans le monde. Il s’agit d”Unicode. Le site http://www.unicode.org/ référence 128 172 caractères.
Si Unicode permet de lever les ambiguïtés concernant l’encodage des caractères, la plupart des logiciels ne sont pas capables d’afficher l’ensemble considérable des caractères encodés.
Si vous choisissez d’afficher des caractères spéciaux assurez vous que le terminal cible soit capable de les afficher.
Pour indiquer à python qu’une chaîne contient des caractères Unicode, il suffit de faire précéder la première guillemet du caractère u
:
s = u"\u263a smile"
# http://www.unicode.org/fr/charts/PDF/U2600.pdf
UTF-8 est une méthode d’encodage des caractères Unicode compatible avec le codage ASCII. C’est le système d’encodage le plus utilisé aujourd’hui.
Représenter une chaîne de caractère :
3.5.1.4. N-uplet (tuple)#
Indication
N-uplet (ou tuple)
Un N-uplet est une séquence non modifiable d’éléments. Ici, on peut assimiler un N-uplet à une liste non modifiable.
Indication
Quand utiliser une N-uplet?
Pour simplifier l’écriture ou pour passer plusieurs paramètres ou valeurs de retour en une seule fois.
Pour modéliser des données non modifiables du programme.
Pour modéliser des clés d’entrée de dictionnaire.
L’utilisation des tuples
peut simplifier l’écriture d’un code python. C’est donc un outil intéressant, mais attention, les données d’un tuple
ne sont pas modifiables.
#création d'un tuple pour décrire un point
origine= 10 , 50 , 90
#sélection d'éléments du tuple
print "x=",origine[0],"y=",origine[1]
#affectation de plusieurs variables avec un tuple
x,y,z= origine
#création d'un tuple à partir d'un liste
t=tuple([1,2,3])
#code produisant une erreur!!!!!
origine[1]=12
À faire
Tester les instructions sur les N-uplet
Représenter un n-uplet/tuple :
t1 = (1,2.,'3') t2 = (t1,":-)",t1[0])![]()
On représentera un tuple par un rectangle contenant des parenthèses. Sur chaque flèche pointant vers une donnée contenue par le tuple nous indiquons le numéro d’ordre de cette donnée. Ainsi il est possible de comprendre l’instruction
t2[2][1]
en regardant les numéros sur les flèches et comprendre que cela pointe vers la valeur2.
3.5.1.5. Listes#
Indication
Liste
Une liste est une séquence variable d’éléments.
Indication
** Quand utiliser une liste? **
(Extraits de cahiers des charges)
« …le personnage possède un certain nombre d’objets dans son inventaire… «
« …une question sera choisie au hasard parmi tous les QCMs disponibles… »
« …il est possible d’afficher les dix meilleurs scores du jeu… «
« …les joueurs posent leurs pions sur une grille de 8 par 8 cases…. »
A la différence des tuple
, les listes sont modifiables. Il existe plusieurs opérations permettant de manipuler les listes. Recherchez et consultez la documentation Python.
#création d'une liste vide
l=[]
#création d'une liste avec des éléments
l=[1,2]
l.append(3)
l.append(4)
for i in l:
print i
#création d'une liste de caractères à partir d'une chaîne de caractères
l=list("toto")
L’utilisation de listes de listes vous permet de créer des grilles en deux dimensions, des plateaux de jeux ou des images…
#image stickman
img=[]
img.append([' ','o',' '])
img.append(['-','|','-'])
img.append([' ','|','\\'])
#on bouge la jambe!
img[2][1]=' '
img[2][0]='/'
Voici un code qui pourrait vous être utile par la suite pour initialiser des grilles vides (on ne vous demande pas de le comprendre!):
matrix = [[0 for x in range(3)] for x in range(2)]
# [ [0,0,0],
# [0,0,0] ]
À faire
Tester les instructions sur les listes
Vous pouvez tester ces instructions pour vérifier que vous êtes à l’aise avec la manipulation des listes.
Représenter une liste :
l1 = [1,2.,'3'] l2 = [t1,":-)",t1[0]]![]()
On représentera une liste par un rectangle contenant des crochets. Sur chaque flèche pointant vers une donnée contenue par la liste nous indiquons le numéro d’ordre de cette donnée. Ainsi il est possible de comprendre l’instruction
l2[2][1]
en regardant les numéros sur les flèches et comprendre que cela pointe vers la valeur2.
3.5.1.6. Dictionnaires#
Indication
Dictionnaire
Un dictionnaire python est un conteneur qui associe des données à une clé. Le dictionnaire appartient à la famille des tables de hachage. La clé est souvent une chaîne de caractères mais peut être une autre donnée hachable (entier, réel, N-uplet).
Indication
Quand utiliser un dictionnaire?
(Extraits de cahiers des charges)
« …Le joueur possède un annuaire qui attribut un numéro à chaque personne rencontrée… »
« …on mémoirise la liste des actions rélaisées à chaque coordonnées de la carte… »
#création
dic = {'prenom': 'Jean', 'nom': 'Dupond'}
#parcours des clés
for cle in dic:
#recupération d'un élément avec la clé
print cle, ":", dic[cle]
#ajout d'un nouvel eleent
dic['tel']='0298056600'
#test de la présence d'une clé
if 'tel' in dic:
print 'Téléphone:', dic['tel']
#suppression d'une entrée du dictionnaire.
del dic['mail']
Représenter un dictionnaire :
d1 = {'name':'bob','health':12,'position':[1,4] } d2 = d1![]()
On représentera un dictionnaire par un rectangle contenant des accolades. Sur chaque flèche pointant vers une donnée contenue par le dictionnaire nous indiquons le numéro la clé. Ainsi il est possible de comprendre l’instruction
d2['position'][1]
en regardant les clés et numero sur les flèches et comprendre que cela pointe vers la valeur2
3.5.1.7. Objets#
Un objet est une donnée qui est utilisée dans la programmation orientée objet.
La notion de programmation orientée objet ne sera abordée qu’en fin de semestre.
À cette étape du cours nous ne définissons que partiellement la notion d’objet.
En fait nous assimilons un objet à un dictionnaire que l’on manipulerait avec une syntaxe différente.
En plus de ça, un objet appartient à un type que nous déclarons avec le mot clé class
Indication
Quand utiliser un objet?
(Extraits de cahiers des charges)
« …Le joueur est caractérisé par un nom, un score, une position… »
« …Pour chaque question, on propose 3 réponses parmi lesquelles la bonne réponse… »
Les objets seront les données que vous utiliserez le plus pour décrire les données de votre jeu. Nous nous en servirons pour implémenter les types abstraits de données (voir cours suivant).
#declaration du type
class Perso: pass
#création
obj=Perso()
obj.prenom="Jean"
obj.nom="Dupond"
#récupération d'une valeur
print(obj.prenom)
#pour obtenir le dictionnaire équivalent:
dic=obj.__dict__
print(dic)
On peut également voir un objet comme un espace de nommage qui nous permet de ranger des variables (prenom
et nom
) dans une variable (obj
)
Représenter un objet :
le code précédent donnerait la représentation suivante :
class : Question class : Answer r=Answer() e.value=4 q=Question() q.text="2+2?" q.answer=aCe code donnerait la représentation suivante :
![]()
On représentera donc un objet par un rectangle contenant le nom de son type (= nom de sa classe). Sur chaque flèche pointant vers une donnée contenue par l’objet nous indiquons la clé. Ainsi il est possible de comprendre l’instruction
q.answer.value
en regardant les clés sur les flèches et comprendre que cela pointe vers la valeur4
3.5.1.8. Exercices#
3.5.1.9. Portée et passage#
Les données sont contenues dans des variables. Vous devez vous rappeler qu’une variable a une portée; c’est à dire qu’elle n’est connue que dans un certain contexte. Par exemple une variable locale n’est connue que dans la fonction dans la quelle on l’utilise.
Par ailleurs, certaines données, selon leur type, sont modifiables ou non modifiables. On parle de type mutable ou non mutable. Il faut bien comprendre que si on passe une donnée non modifiable (entier, réel, chaîne…) en paramètres d’une fonction, cette fonction ne pourra en aucun cas modifier cette donnée. A l’inverse, si la donnée peut être modifiée alors il sera possible pour la fonction de produire un effet sur cette donnée.
Expérimentez le code suivant pour bien identifier la différence entre la modification d’une donnée et la ré-affectation d’un variable.
print 're-affectation:'
#re-affectation
#
a = 1
b = a
#ici les variables a et b ont été affectées avec la même donnée non mofiable : 1
b = b+1
#b a été reaffectee avec un nouvel entier : 2
print 'a=',a
print 'b=',b
print 'a==b --> ',a==b
#seul la valeur de b est modifié
print'\nmodification:'
#modification
#une seule liste manipulée par deux variables
a=[1,2,3]
b=a
b[1]=0 #en modifiant la liste b je modifie aussi a
print 'a=',a
print 'b=',b
print 'a[0]==b[0] --> ',a[0]==b[0]
#a et b font référence à la même liste
3.5.2. Données complexes#
3.5.2.1. Arbres#
Indication
Arbre de données
Un arbre est une structure de données récursive tel que chaque donnée, sauf la racine, possède un unique parent. Un arbre est un graphe particulier. Dans la pratique, nous construirons des arbres avec des dictionnaires, des listes ou des tuples.
Indication
Quand utiliser un arbre de données?
(Extraits de cahiers des charges)
« … Le jeu se compose de joueurs et d’un plateau. Chaque joueur est décrit par un nom, une position, une vitesse. Le plateau se décompose en cases, chaque case contient un mur ou une liste d’objets… »
Dès qu’on commence à utiliser des objets, des dictionnaires ou des listes on commence à construire des arbres de données. Le jeu que vous réaliserez mettra très probablement en œuvre des arbres de données. Il s’agit dans un premier temps d’être capable de représenter graphiquement ces arbres pour pouvoir les penser.
a = 12
b = 'toto'
l = [ a, b ]
c1 = 'clé1'
c2 = 'clé2'
data = { c1: l, c2: None } #les tuple peuvent servir de clé dans un dictionnaire
Vous pouvez représenter l’arbre de données correspondant à la variable data
de la manière suivante. Comprenez vous le lien entre le code précédant et l’image suivante?
Ici le dessin d’une liste de liste de 9 éléments représentant une grille de jeu de Morpion:
Faites vous le lien avec le code suivant?
grille_morpion = [['X','O',' '],['X','X','X'],['O',' ','O']]
Vous devez être capable de lire, modifier et concevoir des arbres de données.
3.5.2.2. Graphes#
Indication
Graphe
un graphe est une collection de données mises en relation entre elles. Un graphe contient des nœuds (les données) et des liens (les relations binaires entre les données). Dans la pratique, non construirons des arbres avec des dictionnaires.
Indication
Quand utiliser un graphe?
« …Le donjon contient plusieurs salles reliées par des portes… »
« …Le jeux reprend le principe des livres dont vous êtes le héros… »
La théorie des graphes est un vaste sujet d’étude. Il existes de nombreux algorithmes de parcours de graphes (on peut citer celui du « voyageur de commerce » qui permet de trouver le plus court chemin pour parcourir l’ensemble des sommets d’un graphe), de preuve, de recherche, de représentation, etc… Ici, nous ne faisons qu’effleurer ce thème en imaginant comment on peut représenter des arcs et des sommets avec des données python et imaginer à quoi peut servir un graphe dans le projet.
Un graphe permet de montrer que des éléments (les sommets) sont en relation (les arcs) avec d’autres éléments. Ces éléments peuvent être des pièces, des niveaux de jeux, des éléments d’histoire ou de scénario, des points sur une carte, etc…
On peut coder les graphes de plein de manières différentes selon comment on souhaite les utiliser. Vous pourrez imaginer votre propre solution. voici trois exemples de codage de graphes :

#Chaque cle du dictionnaire est un sommets
graph = {'A': ['B', 'C'],
'B': ['C', 'D'],
'C': ['D'],
'D': ['C'],
'E': ['F'],
'F': ['C']}
#chaque sommet est un dictionnaire
a={'voisins':[],'nom':'A'}
b={'voisins':[],'nom':'B'}
c={'voisins':[],'nom':'C'}
d={'voisins':[],'nom':'D'}
e={'voisins':[],'nom':'E'}
f={'voisins':[],'nom':'F'}
a['voisins'].append(b)
a['voisins'].append(c)
b['voisins'].append(c)
b['voisins'].append(d)
c['voisins'].append(d)
d['voisins'].append(c)
e['voisins'].append(f)
f['voisins'].append(c)
graphe=[a,b,c,d,e,f]
#liens codes sous forme matricielle
graph = {'sommets': ['A','B','C','D','E','F'],
'arcs' : [[0,1,1,0,0,0],
[0,0,1,1,0,0],
[0,0,0,1,0,0],
[0,0,1,0,0,0],
[0,0,0,0,0,1],
[0,0,1,0,0,0]] }