Micropython : rester "built-in" !

Lorsque l'on se met à coder en Micropython sur microcontrôleur, le nombre de librairies disponibles est moindre qu'en CPython, et du coup, tout une série de choses que l'on aurait fait en appelant telle ou telle librairie en CPython n'est pas possible "as is" en Micropython.

Dans un premier temps, on peut considérer la chose comme frustrant... mais en fait, il y a au passage un enseignement intéressant : lorsque l'on code en CPython sur une plateforme ayant les ressources plus importantes, on s'habitue à utiliser toutes sortes de librairies et parfois pour des choses très simples... et on en arrive à négliger les fonctions ou classes builtins !

L'exemple type est l'utilisation de la librairie Numpy. En CPython, on utilisera volontiers la librairie Numpy pour créer un tableau de valeurs décimales, ce qui typiquement donnera :

import numpy as np

x=np.arange(0,1,0.1)
print(x)
[0.  0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9]

Et pour calculer des coordonnées y à partir de x, on ferait :

y=np.sin(x) # fonction sinus

Et donc, en Micropython, on ne peut pas facilement faire çà. En fait, on peut avec un Micropython compilé avec une version légère de numpy intégrée, mais je me sers de cet exemple à titre d'illustration. En fait, si on y réfléchi bien, dans une situation pareille, on n'a absolument pas besoin de numpy, alors que l'on va volontiers l'utiliser en CPython pour des choses aussi simples.

Avec des list, on peut très bien faire la même chose sans grande difficulté :

start, end, step=3,4,0.1
x=[start+(el*step) for el in range(0,int((end-start)/step))]
print(x)
[3.0, 3.1, 3.2, 3.3, 3.4, 3.5, 3.6, 3.7, 3.8, 3.9]

Vous allez me dire que c'est moins simple qu'un tableau numpy... Bon, ben ok, faîtes vous une petite fonction arange que vous apellerez quand vous en aurez besoin :

 def arange(start, end, step):
    return [start+(el*step) for el in range(0,int((end-start)/step))]

x=arange(3,4,0.1)
print (x)
[3.0, 3.1, 3.2, 3.3, 3.4, 3.5, 3.6, 3.7, 3.8, 3.9]

Et pour calculer y à partir de x, on pourra faire simplement :

import math

y=[math.sin(el) for el in x]
print(y)
[0.1411200080598672,
 0.04158066243329049,
 -0.058374143427580086,
 -0.1577456941432482,
 -0.2555411020268312,
 -0.35078322768961984,
 -0.44252044329485246,
 -0.5298361409084934,
 -0.6118578909427189,
 -0.6877661591839738]

Ce qui, avouez-le est loin d'être la "mer à boire", mais surtout, cela nous fait rester simple... d'autant qu'il n'y a pas besoin de compliquer en l'occurrence !

Conclusion

Donc, en Micropython, il faut un peu se défaire de "mauvaises habitudes" qui consistent à un peu systématiquement utiliser "l'artillerie lourde" y compris pour des choses simples : (Micro)Python est un langage qui disposent de nombreux outils "built-in" qu'il faut prendre le temps de se réapproprier. Et il sera toujours passer à numpy, le cas échéant. Mais garder une approche "built-in" quand c'est possible et surtout pour des choses simples est un réflexe à avoir, indispensable même en MIcroPython sur microcontrôleur.

Une telle approche sera également intéressante en CPython : s'habituer à faire des codes qui utilisent en premier lieu le "built-in" dans la mesure du possible. En tout cas, en Micropython, c'est une obligation.

En sujet connexe à celui-ci, il y a l'intérêt d'un codage avec des "pure function", des fonctions autonomes par elles-mêmes et qui n'utilisent que des éléments built-in. C'est l'objet d'un post séparé.