|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235 |
- % Programmation avec Python (chapitre 14)
- % Dimitri Merejkowsky
-
- \center \huge Parlons de binaire
-
- # Bits et octets
-
- * Un bit (*bit* en anglais) c'est la valeur 1 ou 0
- * Un octet (*byte* en anglais) c'est une suite de 8 bits
-
- # À retenir
-
- **Ces paquets de 8 ne veulent rien dire en eux-mêmes**.
- Ils n'ont de sens que dans le cadre d'une *convention*.
-
- Détaillons.
-
-
- # Bases
-
- On peut *interpréter* bits et octets comme des nombres
-
- ```
- 10: 0..9 305 305 3*100 + 0*10 + 5*1
- 2: 01 5 101 1*4 + 0*2 + 1*1
- 16: 0..9..F 3490 DA2 (d=13)*256 + (a=10)*16 + 2*1
- ```
-
- # Valeurs possibles
-
- Le nombre de valeurs possible augmente *très* rapidement avec le nombre d'octets:
-
- * 1 octet: $2^8$: 255
- * 2 octets: $2^{16}$: 65.536
- * 4 octets: $2^{32}$: 4.294.967.296
- # Bases en Python
-
- ```python
- >>> 5
- 5
- >>> 0b101
- 5
- >>> 0xda2
- 3490
- ```
-
- ```python
- >>> bin(5)
- "0b101"
- >>> hex(3490)
- "0xda2"
- ```
-
- # Poids des bits
-
- ```python
- 0b0010010 # 18
- 0b0010011 # 19
- 0b1010010 # 82
- ```
-
- Le premier bit est plus "fort" que le dernier - little endian
-
- # Manipuler des octets en Python
-
- Avec `bytearray` par exemple:
-
- ```python
- data = bytearray(
- [0b1100001,
- 0b1100010,
- 0b1100011
- ]
- )
- # equivalent:
- data = bytearray([97,98,99])
- # equivalent aussi:
- data = bytearray([0x61, 0x62, 0x63]
- ```
-
-
- # Texte
-
- On peut interpréter des octets comme du texte - c'est la table ASCII
-
- ![ascii table](img/ascii-table.png)
-
- # ASCII - remarques
-
- * C'est *vieux* - 1960
- * Le A est pour American
- * Ça sert à *envoyer* du texte sur des terminaux d'où les "caractères" non-imprimables dans la liste
- * Mais c'est une convention *très* utilisée
- * Techniquement, on n'a besoin que de 7 bits, mais on préfère envoyer des octets
-
- # Utiliser ASCII en Python
-
- Avec `chr` et `ord`
-
- ```python
- >>> chr(98)
- 'b'
- >>> ord('a')
- 97
- ```
-
- # Affichage des bytearrays en Python
-
- Python utilise ASCII pour afficher les bytearrays si les caractères sont "imprimables"
-
- ```python
- >>> data = bytearray([97,98,99])
- >>> data
- bytearray(b"abc")
- ```
-
- Et `\x` et le code hexa sinon:
-
- ```python
- >>> data = bytearray([7, 69, 76, 70])
- >>> data
- bytearray(b"\x07ELF")
- ```
-
- # Types
-
- La variable `b"abc"` est une "chaîne d'octets", de même que `"abc"` est une "chaîne de caractères".
-
- Python apelle ces types `bytes` et `str`:
-
- ```python
- >>> type("abc")
- str
- >>> type(b"abc")
- bytes
- ```
- Notez bien que ce qu'affiche Python n'est qu'une *interpétation* d'une séquence d'octets.
-
- # bits versus bytearray
-
- De la même manière qu'on ne peut pas un caractère dans une string, on ne peut
- pas modifier un bit - ou un octet dans un `bytes`.
-
- ```python
- >>> a = "foo"
- >>> a[0] = "f"
- TypeError: 'str' object does not support item assignment
- >>> b = b"foo"
- >>> b[0] = 1
- TypeError: 'bytes' object does not support item assignment
- ```
-
- # bits versus bytearray (2)
-
- Par contre on peut modifier un bytearray
-
- ```python
- >>> b = bytearray(b"foo")
- >>> b[0] = 103
- >>> b
- bytearray("goo")
- ```
-
- # Conversion octets - texte
-
- Avec `encode()` et `decode()`:
-
- ```python
- >>> text = "hello"
- >>> text.encode("ascii")
- b"hello"
- >>> octets = b"goodbye"
- >>> text = octets.decode("ascii")
- "goodbye"
- ```
-
-
- # Plus loin que l'ASCII
-
- Pas de caractères accentués dans ASCII. Du coup, on a d'autres *conventions* qu'on appelle "encodage".
-
- ```python
- # latin-1: utilisé sur certains vieux sites
- # souvent européens
- >>> bytearray([233]).decode('latin-1')
- 'é'
- ```
-
- ```python
- # cp850: dans l'invite de commande Windows
- >>> bytearray([233]).decode('cp850')
- 'Ú'
- ```
-
- Mais ça, c'était avant.
-
- # UTF-8
-
- * La table unicode - caractère -> codepoint
- * Un encodage qui a mis tout le monde d'accord
- * Compatible avec ASCII
-
- # UTF-8 en pratique
-
- * Certains caractères sont représentés par 2 octets ou plus:
-
- ![utf8 exemple](img/utf8.png)
-
- *note: toutes les séquences d'octets ne sont pas forcément valides*
-
- # Conséquences
-
- * Peut représenter *tout* type de texte (latin, chinois, coréen, langues disparues, ....)
- * On ne peut pas accéder à la n-ème lettre directement dans une chaîne unicode, il faut parcourir lettre par lettre
-
-
- # Fichiers
-
- ```python
- with open("fichier.txt", "r") as f:
- contents = f.read() # type: str
- ```
-
- \vfill
-
- ```python
- with open("fichier.txt", "rb") as f:
- contents = f.read() # type: bytes
- ```
-
- # Conclusions
-
- * On utilise souvent le binaire pour échanger entre Python et le monde extérieur
- * Le 'plain text' n'existe pas: tout texte a un *encodage*, et il vous faut connaître cet encodage
- * Si vous avez le choix, utilisez UTF-8
|