Python et le taoïsme

mercredi 1er avril 2020
par  Alain BUSSER , Sébastien HOARAU

À la question « un chien a-t-il la nature de Bouddha ? » le moine Joshu a répondu « mu (zen) » que qui veut dire « rien » ou « vide ». Le Tao quant à lui conseille d’« agir sans agir » :


La voie reste toujours sans agir,
mais sans elle rien ne se fait.

Nous allons donc voir, avec les bouddhistes Zen, comment le rien peut être modélisé en Python, et ensuite, nous allons rejoindre les taoïstes pour voir comment, toujours en Python, se modélise la non action. En passant on verra également ce qu’est au sens éthymologique, la fainéantise.

Modélisation du rien en Python

Le rien est-il variable ?

L’instruction suivante a pour effet de créer une variable de nom v et d’y mettre du rien :

v = None

En effet l’objet None est vide (il ne possède pas vraiment de valeur, ou plutôt on modélise cette valeur par None). En modélisant mathématiquement une variable par un couple (nom,valeur) ou une boîte contenant une valeur et portant une étiquette avec un nom, la variable de nom v que l’on a créée ci-dessus est une boîte portant l’étiquette « v » mais vide.

Où est le vide ?

En entrant

id(v)

on apprend à quel emplacement de la mémoire vive, se situe cet objet vide. Il n’y a qu’un seul emplacement car il n’y a qu’un seul vide : on dit que le rien est un singleton (patron de conception).

C’est quoi le rien ?

En entrant

type(v)

on a l’affichage

<class 'NoneType'>

qui suggère que le rien est un type.

Que peut-on faire avec rien ?

Pour connaître les méthodes de cet objet vide, on peut entrer dans la console

dir(v)

ce qui donne quelque chose comme

['__bool__', '__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__']

Somme toute, il y a pas mal de choses que l’on peut faire avec le vide !

Peut-on voir le vide ?

Et bien cela dépend. Le vide se pare avant de sortir. Il peut être invisible ou au contraire apparaître clairement aux yeux de tous. Dans la console, entrer v n’a pas le même effet qu’entrer print(v). Dans le premier cas, est invoquée la méthode __repr__ (qui renvoie la chaîne vide et nous est donc invisible) alors que dans le second cas, c’est la méthode __str__ qui est appliquée, et celle-ci renvoie la chaîne de caractères

'None'

Quelle est la taille du vide ?

Puisqu’on a vu que le vide avait un type, qu’on pouvait même le voir, on est en droit de se poser la question : a-t-il une taille ?

v.__sizeof__()

Nous renseigne efficacement :

16

Mais alors, en Python, peut-on être un moins que rien ? Quelques tests nous incitent à penser que non :

x = 0
x.__sizeof__()

nous donne :

24
s = ''
s.__sizeof__()

nous donne :

49

Le vide est-il égal à lui-même ?

Il n’y a qu’à demander à Python :

v == v

La réponse True est éclairante !

La logique du vide

v == True
False
v == False
False

Oh ! Le vide n’est ni vrai ni faux. Pourtant :

if v:
   print('Le vide est vrai')
else:
   print('Le vide est faux')

Nous affiche :

Le vide est faux

En réalité, l’expression

bool(v)

s’évalue à

False


Le vide s’apparente au faux.

Finalement c’est quoi le rien ?

En écrivant

help(v)

on obtient cette description du rien :

Help on NoneType object:
class NoneType(object)
 |  Methods defined here:
 |  
 |  __bool__(self, /)
 |      self != 0
 |  
 |  __new__(*args, **kwargs) from builtins.type
 |      Create and return a new object.  See help(type) for accurate signature.
 |  
 |  __repr__(self, /)
 |      Return repr(self).
(END)

Ceci confirme qu’on peut convertir du rien en proposition logique (on obtient False comme réponse à la question self != 0 ce qui signifie que le vide n’est pas différent de zéro - est-il pour autant égal à 0 ?- non car v==0 donne aussi l’affichage False), qu’on peut créer le vide (mais une seule fois) et qu’il possède une représentation qui est la représentation du vide.


Le vide n’est pas non nul.
Le vide n’est pas nul non plus.

Renvoyer du rien ou ne rien renvoyer ?

Le rien en Haskell

En programmation fonctionnelle, et en particulier en Haskell, l’équivalent du None de Python s’appelle le type unité. Il se note par des parenthèses vides. Pour savoir (avec ghci qui est une console interactive en Haskell) de quel type est le rien, on entre

:t ()

ce qui donne l’affichage suivant :

() :: ()

ce qui signifie que le rien est du type du rien. On s’en doutait un peu quand même.

En Haskell, le rien (appelé unité) sert à définir des fonctions impures comme cette fonction afficher :

let afficher texte = print texte

qui a pour but d’afficher du texte, et non de renvoyer une valeur. Pour connaître son type on demande à Haskell

:t affichage

et on obtient

afficher :: Show a => a -> IO ()

Ce qui est avant le => signifie que si a est un type compatible avec Show (quelque chose qu’on peut montrer) alors la fonction afficher est de type a -> IO () c’est-à-dire le type d’une fonction qui, à a, associe ce qu’on obtient en enveloppant le rien (les parenthèses vides) dans une monade IO (comme « input-output » ; c’est la monade qui contient print).

C’est là l’utilité en Haskell d’avoir du rien : c’est ce rien que renverra une fonction comme afficher qui sert à faire quelque chose (afficher son argument) et non à renvoyer quoi que ce soit : à la place cette « fonction » renvoie du rien.

Ne soyez pas procéduriers, c’est impur

On peut (un peu arbitrairement) classer les fonctions de Python en trois catégories :

  • Les fonctions pures qui ne servent qu’à renvoyer quelque chose (elles ne font pas d’effet de bord) ;
  • les fonctions impures qui renvoyent quelque chose mais, en plus, modifient leur environnement (exemple la méthode pop qui fait sauter le bouchon du saké avant de renvoyer le bouchon) ;
  • les procédures qui ne font que des effets de bord.

Les spécialistes de la programmation fonctionnelle n’aiment pas utiliser le mot « procédure » mais celui-ci est peut-être plus naturel en mathématiques où une fonction a vocation à être composée avec une autre fonction, pas à modifier l’environnement.

Or en Python comme dans les langages fonctionnels il n’y a pas de possibilité de distinguer les fonctions des procédures, on propose en général de remplacer le mot « procédure » par l’expression « fonction ne renvoyant rien ».

Comment Python peut-il ne rien renvoyer ?

2 petits riens

Cette fonction ne renvoie rien :

def rien1():
    return

On verra plus bas que même le mot-clé return est facultatif. Mais ici c’est une instruction (et non une fonction) intimant à la machine l’ordre de quitter le corps de la fonction. Cette fonction ne renvoie donc rien, comme on peut le constater en entrant dans la console rien1() et en constatant que rien n’est affiché (puisque rien n’est renvoyé et que la console devait afficher ce que renvoie la fonction, c’était prévisible).

On obtient exactement la même chose (c’est-à-dire rien) en entrant dans la console rien2() après avoir défini la fonction suivante :

def rien2():
    return None


Ne rien renvoyer ou renvoyer du rien, en Python, c’est pareil.

Les apparences sont-elles trompeuses ?

On ne sait jamais, il se pourrait qu’en cachette les deux fonctions rien1 et rien2 ci-dessus ne fassent pas exactement la même chose dans les arcanes de la machine. Pour en savoir plus on peut utiliser le module de désassemblage de bytecode fourni avec Python. En anglais « désassemblage » se traduit par disassemble et tant le module que la fonction se nomment dis.

On écrit donc

from dis import *

avant les définitions des fonctions rien1 et rien2 puis, après les définitions, dis(rien1) ou dis(rien2) permet de savoir comment chacune est exécutée pas à pas par la machine virtuelle Python.

Les deux fonctions donnent exactement le même bytecode :

 4           0 LOAD_CONST               0 (None)
             3 RETURN_VALUE

Il n’y a, côté assembleur, que deux lignes :

  • La ligne 4 consiste à charger la valeur qui sera renvoyée par la fonction. Il s’agit d’une constante de taille 0 octet et de valeur None.
  • La ligne suivante (3 car il y a eu changement dans la taille de la pile) est le retour de la valeur en question : tout ce qui concernait l’exécution de la fonction est oublié (dépilé) et la constante None est renvoyée à ce moment-là.

Ceci signifie qu’en réalité, renvoyer du rien revient effectivement à ne rien renvoyer, ou plutôt l’inverse : Python insère automatiquement un None derrière return, s’il n’y a rien. Autrement dit, s’il voit un return sans rien derrière, il considère que ce rien est None (ce qu’on ne peut guère lui reprocher) et renvoie None, comme s’il avait vu return None.

Faire du rien

3 fois rien

Et si on essayait de ne même pas mettre de ligne avec return ?

Pas si facile : si on essaye d’entrer

def rien3():
   

on a un message d’erreur sur l’indentation non respectée après le double-point (une ligne vide n’est pas une ligne indentée).

Pour éviter ce désagrément on peut, ou bien mettre quelque chose d’inutile genre a=a ou bien faire

def rien3():
    pass

Cette nouvelle fonction donne exactement le même bytecode que les deux précédentes comme on peut le vérifier en la soumettant à la fonction dis de désassemblage.

L’instruction la plus taoïste de Python est assurément ce pass qui ne fait rien. La présence d’une telle instruction ne faisant rien n’est pas spécifique à Python, par exemple la plupart des assembleurs possèdent une instruction NOP qui a le même effet. Rappelons qu’une instruction est un ordre donné à la machine lorsqu’on veut qu’elle fasse quelque chose (affecter une variable, afficher un résultat, etc). Mais ici on veut que la machine ne fasse rien. C’est néanmoins une instruction.


L’eau est faible
De ce qui est fort
rien ne la passe
rien ne prend sa place

(Lao Tseu)

Sage, passage et repassage

Quitte à ne rien faire, pourquoi pas le (pas) faire plusieurs fois ?

La fonction suivante accepte un entier n en entrée, puis répète n fois l’action (ou plutôt la non-action) de ne rien faire :

from time import *
def repassage(n):
    t = time()
    for _ in range(n):
        pass
    return time()-t

Noter que si on appelle la fonction avec un argument nul, elle ira encore plus loin que ne rien faire puisqu’elle fera rien, zéro fois. Y a-t-il une langue au monde qui possède un verbe pour cette non-action (ne rien faire, mais zéro fois) ?

En fait la fonction repassage n’est pas sage : Elle chronomètre le temps pris à ne rien faire. Et il semble intéressant d’évaluer ce temps, notamment pour de grandes valeurs de n. Ce script le permet :

from matplotlib.pyplot import * # ligne à placer au tout début du script
zen = [repassage(n) for n in range(1000)]
plot(range(1000),zen,'b.')
show()

Le résultat est que mine de rien ça prend quand même un peu de temps, de ne rien faire (même si n est égal à zéro : le temps de l’appel à la fonction) :

On voit que la droite ne passe pas tout-à-fait par l’origine : Ne rien faire zéro fois prend très peu de temps mais un peu de temps quand même. Par contre la paresse itérée est plus chronophage que la paresse occasionnelle.

Le sage ne fait que passer dans le Tao

Mais à quoi peut donc servir cette instruction qui ne fait rien ? C’est une histoire de gabarit. Par exemple, lorsqu’on veut créer son propre objet, on a intérêt à donner la liste des méthodes avant de voir comment on programme les méthodes. On commencera donc typiquement à écrire quelque chose comme

class MonObjet():
    def méthode1(self):
        pass
    def méthode2(self):
        pass

Ensuite on teste avec un script du genre

o = MonObjet()
o.méthode1()
o.méthode2()

S’il n’y a aucun message d’erreur, et dans ce cas seulement, on commence à réfléchir à ce qu’on va mettre à la place des pass.

On a vu une autre application de cette instruction dans cet article : Les méthodes des variables de Sofus ne sont pas accessibles depuis le menu des fonctions de la calculatrice, et il est donc pratique de créer des fonctions globales ayant le même nom, mais ne faisant rien. Elles ne font donc que passer à la fin de ce script.

Selon Dana Scott et Christopher Strachey, une instruction est la requête d’un effet de bord. Or l’instruction nulle n’a pas d’effet de bord. Doit-on alors la considérer comme une instruction, ou pas ? ou pass ?


Commentaires

Annonces

Prochains rendez-vous de l’IREM

En raison de la pandémie, aucune activité en présentiel n’est prévue dans l’immédiat.


Brèves

Décès de 2 spécialistes des jeux mathématiques

dimanche 29 mars

Après Elwyn Berlekamp l’année dernière, c’est au tour du centenaire Richard Guy et de l’immense John Conway. Ce document de Richard Guy (une mise en garde contre le raisonnement inductif) montre bien le style unique de son auteur, en plus d’être une mine de ressources pour des exercices. Conway, outre son jeu de la vie, a créé des dizaines de jeux, dont Sprouts, très populaire dès le CP.

Python au bac 2019

vendredi 31 mai 2019

C’est une brève de MathemaTICE

La question 4b de l’exercice 3 du bac S Amérique du Nord ne pouvait être résolue sans utiliser Python.

Elwyn Berlekamp

jeudi 18 avril 2019

Elwyn Berlekamp, connu des lecteurs de ce site pour son jeu des interrupteurs, était un spécialiste du jeu de Go ainsi que de la Pipopipette, d’Édouard Lucas que Berlekamp admirait énormément.

Notation au bac

lundi 11 décembre 2017

Une nouvelle notation sera pratiquée à partir de la session 2018 pour les algorithmes au bac. Elle est décrite avec de nombreux exemples, ici.

Décès de Roger Mohr

mardi 27 juin 2017

On sait bien que Nicolas Bourbaki n’était pas le nom d’une personne mais le pseudonyme d’un groupe. L’équivalent en informatique théorique est Claude Livercy, auteur de la théorie des programmes. Roger Mohr était un des membres de Claude Livercy.

À travers les labyrinthes : algorithmes et fourmis

dimanche 1er septembre 2013

Quand les chercheurs mettent au point des modèles d’optimisation et de recherche de plus court chemin qui s’inspirent du comportement de masse de colonies de fourmis...
À écouter : Sur les Épaules de Darwin, émission diffusée sur France Inter samedi 31 août 2013.

Rencontres Mondiales du Logiciel Libre à St-Joseph

mardi 20 août 2013

Les RMLLd se dérouleront pour la 2e fois à Saint-Joseph du 22 au 25 août.
C’est une opportunité pour les élèves qui suivent la spécialité ISN et les passionnés d’informatique.

Voici pour le samedi et le dimanche quelques interventions choisies :
- http://2013.d.rmll.info/Raspberry-votre-ordinateur-au-format-carte-de-credit?lang=fr
- http://2013.d.rmll.info/Materiel-libre-et-DIY?lang=fr
- http://2013.d.rmll.info/Arduino-de-l-electronique-libre?lang=fr

Noter aussi les conférences Art et Culture du dimanche, ainsi qu’une conférence plus engagée.

Le programme complet se trouve ici. Une radio sera ouverte pour l’occasion.
Des plaquettes à distribuer se trouvent ici.

Hyper-vidéos pour l’algorithmique au lycée

dimanche 19 août 2012

Olivier Roizès, à la demande de l’ADIREM, a réalisé une collection d’hyper-vidéos de présentation de logiciels et environnements de programmation. Ces hyper-vidéos, c’est-à-dire des vidéos contenant des éléments clicables, devraient être utiles aux enseignants désireux de se familiariser avec Python, CaRMetal, R, Rurple, Scilab ou Xcas.

Ouverture du SILO

mardi 1er novembre 2011

Le SILO (Science Informatique au Lycée : Oui !) est un espace collaboratif documentaire de partage et de formation collégiale, à destination des professeurs appelés à enseigner l’informatique au lycée.

Une initiative du CNDP, de l’INRIA et de Pasc@line, à laquelle se sont associés SPECIF, fuscia, EPI et ePrep.

Sur le Web : Site du SILO

Introduction à la science informatique

lundi 12 septembre 2011

Le CRDP de Paris publie le premier ouvrage destiné aux professeurs chargés d’enseigner la nouvelle spécialité « Informatique et sciences du numérique » en Terminale S à la rentrée 2012. Cet ouvrage a été coordonné par Gilles Dowek, directeur de recherche à l’INRIA.

Sur la création de la spécialité ISN, on pourra également consulter l’interview donnée au Café pédagogique par l’inspecteur général Robert Cabanne.

Sur le Web : CRDP de Paris

Statistiques

Dernière mise à jour

jeudi 28 mai 2020

Publication

863 Articles
Aucun album photo
142 Brèves
11 Sites Web
151 Auteurs

Visites

80 aujourd'hui
2203 hier
3396508 depuis le début
18 visiteurs actuellement connectés