Quelques pistes pour travailler le programme officiel NSI à partir de Python

1 - Représentation des données: types et valeurs de base

Etienne Lozes -- Pâques 2019

1.1 Écriture d'un entier positif en base b

Les entiers en Python ne sont pas des entiers "machine" sur 32 ou 64 bits, ce sont des entiers mathématiques "non bornés". On peut cependant demander d'afficher un entier en binaire ou en hexadécimal, et saisir un entier en binaire ou en hexadécimal.

In [1]:
hex(42)
Out[1]:
'0x2a'
In [2]:
bin(42)
Out[2]:
'0b101010'
In [3]:
0x11
Out[3]:
17
In [4]:
0b11
Out[4]:
3

Il est intéressant d'expliquer comment les opérations de quotient et reste permettent de retrouver l'écriture en base b d'un nombre, en partant de la base 10. Par exemple, si je veux afficher un nombre en base 3, je peux utiliser la méthode suivante.

In [5]:
def base3(n):
    if n < 3 :
        print(n, end='')
    else :
        base3(n // 3)
        print(n % 3, end='')

base3(42)
1120

1.2 Représentation binaire d'un entier relatif

1.3 Représentation approximative des nombres réels: notion de nombre flottant

Les calculs avec des flottants sont toujours inexacts, il ne faut donc pas s'attendre à ce qu'un test d'égalité entre deux flottants soit exact

In [6]:
a = 10.0 ** 100 
b = a + 10.0 ** -100
a == b
Out[6]:
True
In [7]:
0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 == 0.7
Out[7]:
True
In [8]:
0.1 + 0.1 + 0.1 == 0.3
Out[8]:
False
In [9]:
from math import sqrt
sqrt(2) ** 2
Out[9]:
2.0000000000000004

Signalons enfin les flottants $-\infty$ et $+\infty$, bien pratiques dans certaines situations, par exemple comme élément neutre de min et max.

In [10]:
import math
def minimum(L) :
    """renvoie le minimum de la liste L, plus l'infini si L=[]"""
    res = math.inf
    for x in L :
        if x < res :
            res = x
    return res
In [11]:
minimum([1,2,3])
Out[11]:
1
In [12]:
minimum([])
Out[12]:
inf

1.4 Valeurs booléenes et opérateurs booléens

On peut signaler que Python, sous l'influence du langage C, convertit à la volée les entiers en booléens et vice-versa

In [13]:
0 == False
Out[13]:
True
In [14]:
1 == True
Out[14]:
True
In [15]:
 1 + True
Out[15]:
2
In [16]:
if 1 : print('1->True')
1->True

Les opérateurs booléens paresseux sont bien utiles pour éviter de provoquer des erreurs dans des tests

In [17]:
x = 0
if x != 0 and 1 / x == 3 : print('x vaut 1/3')
In [18]:
if 1 / x == 3 and x != 0 : print('x vaut 1/3')
---------------------------------------------------------------------------
ZeroDivisionError                         Traceback (most recent call last)
<ipython-input-18-85de3a86c2e5> in <module>
----> 1 if 1 / x == 3 and x != 0 : print('x vaut 1/3')

ZeroDivisionError: division by zero

1.5 Représentation d'un texte en machine

On peut retrouver le point de code unicode d'un caractère ou obtenir le caractère correspondant à un point de code donné avec les fonctions chr et ord

In [19]:
ord('a'),ord('b'),ord('é'), ord('€')
Out[19]:
(97, 98, 233, 8364)
In [20]:
chr(32), chr(64), chr(257), chr(49829)
Out[20]:
(' ', '@', 'ā', '슥')

On peut aussi voir les différents encodages possibles d'une chaîne de caractères comme suite d'octets, et les erreurs de décodage qui peuvent en résulter.

In [21]:
s1 = 'une chaine sans accent facile a representer en ASCII'
s1.encode('ASCII')
Out[21]:
b'une chaine sans accent facile a representer en ASCII'
In [22]:
s2 = "une chaîne qu'on peut représenter en Latin 1 ou UTF 8, mais pas en ASCII à cause des accents"
s2.encode('latin-1')
Out[22]:
b"une cha\xeene qu'on peut repr\xe9senter en Latin 1 ou UTF 8, mais pas en ASCII \xe0 cause des accents"
In [23]:
s2.encode('utf-8')
Out[23]:
b"une cha\xc3\xaene qu'on peut repr\xc3\xa9senter en Latin 1 ou UTF 8, mais pas en ASCII \xc3\xa0 cause des accents"
In [24]:
s2.encode('ASCII')
---------------------------------------------------------------------------
UnicodeEncodeError                        Traceback (most recent call last)
<ipython-input-24-2aa70292e6ab> in <module>
----> 1 s2.encode('ASCII')

UnicodeEncodeError: 'ascii' codec can't encode character '\xee' in position 7: ordinal not in range(128)
In [25]:
s3 = "1€, c'est déjà trop cher pour latin 1"
In [26]:
s3.encode('utf-8')
Out[26]:
b"1\xe2\x82\xac, c'est d\xc3\xa9j\xc3\xa0 trop cher pour latin 1"
In [27]:
s3.encode('latin-1')
---------------------------------------------------------------------------
UnicodeEncodeError                        Traceback (most recent call last)
<ipython-input-27-a0ce001c0cac> in <module>
----> 1 s3.encode('latin-1')

UnicodeEncodeError: 'latin-1' codec can't encode character '\u20ac' in position 1: ordinal not in range(256)
In [28]:
"ça c'est une erreur de décodage".encode('utf-8').decode('latin-1')
Out[28]:
"ça c'est une erreur de décodage"