Skip to content

Commit d39d2de

Browse files
committed
normalize file-formats
1 parent 666d86a commit d39d2de

File tree

2 files changed

+424
-22
lines changed

2 files changed

+424
-22
lines changed
Lines changed: 376 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,376 @@
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

Comments
 (0)