% Programmation avec Python (chapitre 14) % Dimitri Merejkowsky
\center \huge Parlons de binaire
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.
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
Le nombre de valeurs possible augmente très rapidement avec le nombre d’octets:
>>> 5
5
>>> 0b101
5
>>> 0xda2
3490
>>> bin(5)
"0b101"
>>> hex(3490)
"0xda2"
0b0010010 # 18
0b0010011 # 19
0b1010010 # 82
Le premier bit est plus “fort” que le dernier - little endian
Avec bytearray
par exemple:
data = bytearray(
[0b1100001,
0b1100010,
0b1100011
]
)
# equivalent:
data = bytearray([97,98,99])
# equivalent aussi:
data = bytearray([0x61, 0x62, 0x63]
On peut interpréter des octets comme du texte - c’est la table ASCII
Avec chr
et ord
>>> chr(98)
'b'
>>> ord('a')
97
Python utilise ASCII pour afficher les bytearrays si les caractères sont “imprimables”
>>> data = bytearray([97,98,99])
>>> data
bytearray(b"abc")
Et \x
et le code hexa sinon:
>>> data = bytearray([7, 69, 76, 70])
>>> data
bytearray(b"\x07ELF")
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
:
>>> 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.
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
.
>>> 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
Par contre on peut modifier un bytearray
>>> b = bytearray(b"foo")
>>> b[0] = 103
>>> b
bytearray("goo")
Avec encode()
et decode()
:
>>> text = "hello"
>>> text.encode("ascii")
b"hello"
>>> octets = b"goodbye"
>>> text = octets.decode("ascii")
"goodbye"
Pas de caractères accentués dans ASCII. Du coup, on a d’autres conventions qu’on appelle “encodage”.
# latin-1: utilisé sur certains vieux sites
# souvent européens
>>> bytearray([233]).decode('latin-1')
'é'
# cp850: dans l'invite de commande Windows
>>> bytearray([233]).decode('cp850')
'Ú'
Mais ça, c'était avant.
note: toutes les séquences d’octets ne sont pas forcément valides
with open("fichier.txt", "r") as f:
contents = f.read() # type: str
\vfill
with open("fichier.txt", "rb") as f:
contents = f.read() # type: bytes