|
| 1 | +--- |
| 2 | +jupytext: |
| 3 | + text_representation: |
| 4 | + extension: .md |
| 5 | + format_name: myst |
| 6 | +kernelspec: |
| 7 | + display_name: Python 3 (ipykernel) |
| 8 | + language: python |
| 9 | + name: python3 |
| 10 | +language_info: |
| 11 | + name: python |
| 12 | + nbconvert_exporter: python |
| 13 | + pygments_lexer: ipython3 |
| 14 | +--- |
| 15 | + |
| 16 | +# fichiers et formats |
| 17 | + |
| 18 | ++++ |
| 19 | + |
| 20 | +Licence CC BY-NC-ND, Thierry Parmentelat & Aurélien Noce |
| 21 | + |
| 22 | ++++ {"tags": ["prune-cell"]} |
| 23 | + |
| 24 | +````{admonition} nothing to prune |
| 25 | +:class: warning |
| 26 | +
|
| 27 | +there are no difference - apart from this very cell - between the teacher and the student version, but the notebook is duplicated in .teacher for consistency |
| 28 | +```` |
| 29 | + |
| 30 | ++++ |
| 31 | + |
| 32 | +```{admonition} commencez par télécharger le zip |
| 33 | +{download}`vous aurez besoin du zip qui se trouve ici<./ARTEFACTS-files-formats.zip>` |
| 34 | +``` |
| 35 | + |
| 36 | ++++ |
| 37 | + |
| 38 | +## on va faire quoi ? |
| 39 | + |
| 40 | +- les fichiers et l'OS; comment ouvrir, pourquoi fermer ? |
| 41 | +- différents formats de fichier usuels |
| 42 | + - texte simple sans accent, typiquement en anglais (ASCII) |
| 43 | + - texte standard (utf-8) |
| 44 | + - pickle (ouille ça pique, c'est du binaire) |
| 45 | + - json (on se sent un peu mieux) |
| 46 | + - csv (ah là on parle) |
| 47 | + - yaml (de plus en plus populaire) |
| 48 | +- comment parser un format de fichier *custom* |
| 49 | + |
| 50 | ++++ |
| 51 | + |
| 52 | +### modalités du TP |
| 53 | + |
| 54 | +- on ouvre vs-code |
| 55 | +- on participe |
| 56 | + |
| 57 | ++++ |
| 58 | + |
| 59 | +## les fichiers et l'OS |
| 60 | + |
| 61 | +c'est quoi l'OS ? |
| 62 | + |
| 63 | +- votre code ne cause **jamais directement** au harware |
| 64 | +- mais toujours au travers d'**abstractions exposées par l'OS** |
| 65 | +- parmi lesquelles, entre autres, la **notion de "fichier"** |
| 66 | + |
| 67 | +```{image} operating_system_placement.png |
| 68 | +:align: right |
| 69 | +:width: 250px |
| 70 | +``` |
| 71 | + |
| 72 | ++++ |
| 73 | + |
| 74 | +### questions préliminaires |
| 75 | + |
| 76 | +- qu'est-ce qu'un fichier ? |
| 77 | +- que contient un fichier ? |
| 78 | +- quelles sont les étapes pour y accéder ? |
| 79 | + |
| 80 | ++++ |
| 81 | + |
| 82 | +## lire un fichier simple |
| 83 | + |
| 84 | +(le fichier `hello.txt` fait partie du zip) |
| 85 | + |
| 86 | ++++ |
| 87 | + |
| 88 | +### ouverture d'un fichier |
| 89 | + |
| 90 | +```{code-cell} ipython3 |
| 91 | +f = open("hello.txt") |
| 92 | +``` |
| 93 | + |
| 94 | +- que se passe-t-il ? |
| 95 | +- pensez à consulter la documentation (comment on la trouve ?) |
| 96 | +- que peut-on faire de `f` ? |
| 97 | +- que pensez-vous de cette version alternative ? |
| 98 | + ```python |
| 99 | + # ça marche aussi; quelle différence ? |
| 100 | + |
| 101 | + f = open("hello.txt", encoding="utf-8") |
| 102 | + ``` |
| 103 | + |
| 104 | ++++ |
| 105 | + |
| 106 | +### les types |
| 107 | + |
| 108 | +- analyser les types des différents objets |
| 109 | + ```python |
| 110 | + type("hello.txt") |
| 111 | + type(f) |
| 112 | + ``` |
| 113 | +- avancer étape par étape |
| 114 | + |
| 115 | ++++ |
| 116 | + |
| 117 | +### il faut fermer ! |
| 118 | + |
| 119 | +que se passe-t-il si on oublie de fermer le fichier ? |
| 120 | + |
| 121 | +> on va écrire un code qui ouvre `n` fichiers |
| 122 | +> le faire tourner avec `n`= 10, 100, 1000, ... |
| 123 | +
|
| 124 | +pouvez-vous prédire ce qui va passer ? |
| 125 | + |
| 126 | ++++ |
| 127 | + |
| 128 | +## l'idiome pour lire un fichier: `with` & `for` |
| 129 | + |
| 130 | +````{admonition} toujours utiliser with |
| 131 | +:class: important |
| 132 | +
|
| 133 | +l'idiome à **toujours utiliser** pour lire un fichier texte |
| 134 | +
|
| 135 | +```python |
| 136 | +# TOUJOURS lire ou écrire un fichier avec un with ! |
| 137 | +
|
| 138 | +with open("hello.txt") as f: |
| 139 | + for line in f: |
| 140 | + print(line, end="") |
| 141 | +``` |
| 142 | +
|
| 143 | +quelles autres formules connaissiez-vous pour faire ça ? |
| 144 | +```` |
| 145 | + |
| 146 | + |
| 147 | +````{admonition} pourquoi le end="" ? |
| 148 | +:class: admonition-small |
| 149 | +
|
| 150 | +à chaque itération, vous allez trouver dans la variable `line`, eh bien la ligne suivante évidemment, |
| 151 | +sauf que ceci **contient un caractère de fin de ligne** - qu'on appelle aussi *newline* |
| 152 | +du coup si vous faites un `print(line)` (essayez..) vous allez avoir une ligne blanche sur deux ! |
| 153 | +
|
| 154 | +une autre approche consisterait à utiliser `line.rstrip()` qui enlève l'éventuel *newline*; |
| 155 | +je dis éventuel car la dernière ligne ne contient pas toujours ce fameux *newline*; le monde est compliqué parfois... |
| 156 | +
|
| 157 | +**exercice**: dans *vs-code*, allez enlever le dernier *newline* (mettez vous à la fin du fichier et faites un *Delete*) |
| 158 | +et refaites tourner les 3 lignes ci-dessus; vous pouvez aussi regarder ce que donne `cat hello.txt` dans le terminal. |
| 159 | +```` |
| 160 | + |
| 161 | ++++ |
| 162 | + |
| 163 | +## contenu des fichiers texte |
| 164 | + |
| 165 | +on va regarder dans les yeux deux fichiers texte: |
| 166 | + |
| 167 | ++++ |
| 168 | + |
| 169 | +### ASCII |
| 170 | + |
| 171 | +- installez l'extension vscode *Hex Editor* |
| 172 | +- regarder le contenu de `hello.txt` avec vs-code |
| 173 | + - utilisez *clic droit* -> *Open With* -> *Hex Editor* |
| 174 | +- comparez avec <https://www.rapidtables.com/code/text/ascii-table.html> |
| 175 | + |
| 176 | ++++ |
| 177 | + |
| 178 | +### Unicode |
| 179 | + |
| 180 | +faites pareil avec `bonjour.txt` |
| 181 | + |
| 182 | +- que constatez-vous ? |
| 183 | +- voyez aussi <https://www.utf8-chartable.de/> |
| 184 | + |
| 185 | ++++ |
| 186 | + |
| 187 | +## un fichier binaire |
| 188 | + |
| 189 | +faites pareil avec `tiny.pickle` |
| 190 | + |
| 191 | +- ouvrez-le "normalement" |
| 192 | + (pour l'instant sans utiliser la librairie `pickle`) |
| 193 | +- comment faut-il adapter le code ? |
| 194 | + *indice*: il faut utiliser le **mode d'ouverture** et spécifier **binaire** |
| 195 | +- que constatez-vous ? (indice: les types !) |
| 196 | + |
| 197 | +````{admonition} à retenir : texte ou binaire |
| 198 | +:class: seealso |
| 199 | +
|
| 200 | +un fichier peut contenir |
| 201 | +
|
| 202 | +- du texte (qu'il faut alors décoder, généralement avec `encoding='UTF-8'`), on obtient alors un `str` |
| 203 | +- du binaire - on obtient alors des `bytes`; dans ce cas on n'a pas besoin de fournir un encodage pour lire le fichier *of course...* - par contre c'est souvent l'application, ou une librairie, qui va se taper le décodage, plus ou moins *à la main* selon les cas. |
| 204 | +```` |
| 205 | + |
| 206 | ++++ |
| 207 | + |
| 208 | +## les différents formats de fichier |
| 209 | + |
| 210 | +Tout le monde ne crée pas sa propre structure (on dit aussi format) de fichier ! |
| 211 | +Il existe des formats ***standard*** qui permettent une interaction entre les programmes, et même différents langages de programmation ! |
| 212 | + |
| 213 | ++++ |
| 214 | + |
| 215 | +### le format pickle |
| 216 | + |
| 217 | +c'est le format *intégré* de Python: |
| 218 | + |
| 219 | +- c'est un format binaire: s'ouvre avec `open(name, 'rb')` |
| 220 | +- permet de sérialiser notamment les types de base, c-a-d non seulement des atomes (nombres, chaines...) |
| 221 | +- mais aussi des **structures plus complexes**, avec des containers etc... |
| 222 | +- par contre, il ne va pas convenir pour échanger avec d'autres langages... |
| 223 | + |
| 224 | +````{admonition} b pour binaire |
| 225 | +:class: note admonition-small |
| 226 | +
|
| 227 | +dans `open(name, 'rb')` le `r` est pour *read* et le `b` pour *binary* |
| 228 | +```` |
| 229 | + |
| 230 | +à faire: |
| 231 | + |
| 232 | +- lisez la documentation du module `pickle` |
| 233 | +- essayez de lire le fichier `tiny.pickle` |
| 234 | +- inspectez les types des objets dans la donnée |
| 235 | + |
| 236 | ++++ |
| 237 | + |
| 238 | +#### pickle : écriture |
| 239 | + |
| 240 | +- partez de ce que vous venez de lire |
| 241 | +- modifiez certaines des données |
| 242 | +- sauvegardez-les dans un nouveau fichier |
| 243 | + `tiny-changed.pickle` |
| 244 | +- et relisez-le pour vérifier que "ça marche" |
| 245 | + |
| 246 | ++++ |
| 247 | + |
| 248 | +### autre format: json |
| 249 | + |
| 250 | +à vous de jouer |
| 251 | + |
| 252 | +- on va refaire pareil à partir de `tiny.json` |
| 253 | +- lisez-la doc et écrivez le code qui lit ce fichier |
| 254 | +- modifiez la donnée lue, et sauvez-la |
| 255 | +- est-ce qu'on peut y mettre un ensemble ? ou un tuple ? |
| 256 | + |
| 257 | ++++ |
| 258 | + |
| 259 | +### encore un: yaml |
| 260 | + |
| 261 | +- trouvez la doc de `PyYAML` |
| 262 | +- lisez le fichier `tiny.yaml` |
| 263 | +- comment peut-on comparer avec JSON ? |
| 264 | + |
| 265 | +```{admonition} et avec annotations ? |
| 266 | +
|
| 267 | +en option: par défaut le format YAML permet de stocker - comme JSON - les types communs aux autres langages, |
| 268 | +i.e. booléens, nombres, chaines, listes et dictionnaires; il est possible aussi de stocker des types un peu moins communs comme le tuple et l'ensemble, au prix d'une gymnastique déjà un peu oins facile d'accès; arrivez-vous à lire le fichier `small-annotated.yaml` ? |
| 269 | +ça peut demander une plangée dans SO (stackoverflow)... |
| 270 | +
|
| 271 | +``` |
| 272 | + |
| 273 | ++++ |
| 274 | + |
| 275 | +### et aussi: les csv |
| 276 | + |
| 277 | +on recommence (c'est optionnel, si vous savez déjà lire un csv avec pandas)... |
| 278 | + |
| 279 | +- lisez la documentation du module `csv` |
| 280 | + google `python module csv` |
| 281 | +- essayez de lire le fichier `pokemon.csv` |
| 282 | +- sauriez-vous créer une dataframe ? |
| 283 | + - version facile: avec `pd.read_csv()` |
| 284 | + - un peu moins simple: sans utiliser `pd.read_csv()` |
| 285 | + |
| 286 | ++++ |
| 287 | + |
| 288 | +## formats custom |
| 289 | + |
| 290 | +comment peut-on lire (on dit *parse*) des formats de fichiers inconnus ? |
| 291 | +pour cela, 2 armes |
| 292 | + |
| 293 | +* le type `str` fournit plein de méthodes - notamment `strip()`, `split()` et `join()` |
| 294 | +* le module `re` (pour *regular expressions*) peut également être utile |
| 295 | + |
| 296 | ++++ |
| 297 | + |
| 298 | +### exercice: lisez `notes.txt` |
| 299 | + |
| 300 | +* sans importer de module additionnel, |
| 301 | +* lisez le fichier `notes.txt` |
| 302 | +* créez et affichez un dictionnaire |
| 303 | + *nom élève* → note |
| 304 | + |
| 305 | +````{admonition} un mot sur print() |
| 306 | +
|
| 307 | +- c'est l'opération la plus simple pour sauver un résultat.. |
| 308 | + mais ce n'est pas très utile en réalité, car le plus souvent limitée à un lecteur humain |
| 309 | +- il est souvent plus utile de sauver ses résultats dans un des formats qu'on vient de voir - typiquement json ou csv |
| 310 | +- mais pour info, on peut écrire dans un fichier `f` (ouvert en écriture) avec `print(des, trucs, file=f)` |
| 311 | +```` |
| 312 | + |
| 313 | +````{admonition} les redirections de bash (pour info) |
| 314 | +:class: admonition-small |
| 315 | +
|
| 316 | +- quand il est lancé, votre programme a un `stdin` et un `stdout` (et un `stderr` mais c'est plus anecdotique) |
| 317 | +- qui sont créés par bash (et sont branchés sur le terminal) |
| 318 | +- vous pouvez les rediriger en faisant |
| 319 | + ```bash |
| 320 | + python myhack.py < the-input > the-output |
| 321 | + ``` |
| 322 | +```` |
| 323 | + |
| 324 | ++++ |
| 325 | + |
| 326 | +### exercice: écrivez un programme |
| 327 | + |
| 328 | +* qui lit sans fin le texte entré dans le terminal |
| 329 | +* regarde si le texte commence par un `q` |
| 330 | +* si oui c'est la fin du programme |
| 331 | +* sinon affiche le nombre de mots dans la ligne |
| 332 | + et recommence |
| 333 | + |
| 334 | +````{admonition} consigne |
| 335 | +
|
| 336 | +ne pas utiliser `input()`, mais plutôt `sys.stdin` |
| 337 | +```` |
| 338 | + |
| 339 | +````{admonition} indices |
| 340 | +:class: tip |
| 341 | +
|
| 342 | +* de quel type est `sys.stdin` ? |
| 343 | +* si vous voulez ajouter un *prompt* |
| 344 | + (un peu comme les `>>>` de python) |
| 345 | + lancez votre programme avec `python -u mycode.py` |
| 346 | +```` |
| 347 | + |
| 348 | ++++ |
| 349 | + |
| 350 | +## épilogue: les *regexps*, en deux mots |
| 351 | + |
| 352 | +sans transition.. |
| 353 | + |
| 354 | +* l'idée est de décrire une *famille* de chaines |
| 355 | +* à partir d'une autre chaine (la *regexp*) |
| 356 | +* qui utilise des opérateurs |
| 357 | + * comme p.e. `*` |
| 358 | + * pour indiquer 'un nombre quelconque de fois' telle ou telle autre *regexp* |
| 359 | + |
| 360 | + |
| 361 | + exemple de *regexp* |
| 362 | + |
| 363 | +`ab((cd)|(ef))*` décrit un ensemble qui |
| 364 | + |
| 365 | +* ne contient que des mots qui commencent par `ab` |
| 366 | +* contient `abcd` et aussi `abef` |
| 367 | +* ou encore `abcdcdefcd` |
| 368 | +* mais pas `abce` ni `abcde` |
| 369 | + |
| 370 | +````{admonition} avertissement |
| 371 | +
|
| 372 | +> Some people, when confronted with a problem, think |
| 373 | +“I know, I'll use regular expressions.” Now they have two problems. |
| 374 | +
|
| 375 | +<http://regex.info/blog/2006-09-15/247> |
| 376 | +```` |
0 commit comments