recher – Sam & Max http://sametmax.com Du code, du cul Wed, 30 Oct 2019 15:34:04 +0000 en-US hourly 1 https://wordpress.org/?v=4.9.7 32490438 Des idées que j’aurai jamais le temps de faire. http://sametmax.com/des-idees-que-jaurais-jamais-le-temps-de-faire/ http://sametmax.com/des-idees-que-jaurais-jamais-le-temps-de-faire/#comments Wed, 05 Nov 2014 11:01:08 +0000 http://sametmax.com/?p=12601

Ceci est un post invité de Réchèr sous licence creative common 3.0 unported.

Mon cerveau est absolument génial. Il trouve tout le temps un tas de projets super. Le problème c’est que mon corps est une grosse feignasse, et ne prend jamais le temps ni le courage de les réaliser. Du coup, je me retrouve avec un tas de bazar dans la tête dont je ne ferais jamais rien. Le mieux, c’est de l’offrir au monde.

Il y a un peu de tout : du potentiellement intéressant, du bien débile, et du carrément glauque. C’est en vrac, faites en ce que vous voulez.

Et puisque ça semble être une tradition pour les articles longs : un peu de musique.

Chocolate DB

“Maintenant, vous savez sur quoi vous allez tomber”

ipad_chocolate_ichocolates

Repas de Noël en famille. Au moment du café, votre grand-mère pose la traditionnelle boîte de chocolat sur la table. Votre tante est allergique aux noix, votre cousin converti à l’islam ne boit plus d’alcool, y compris sous forme de liqueur, et vous, vous voudriez éviter le caramel car ça colle aux dents. Comme chaque année, votre grand-mère a jeté le papier de description de la boîte, parce que “c’est écrit trop petit dessus”.

Le site de recensement Chocolate DB est là pour vous sortir de ce genre de situation délicate, avec des informations détaillées et individuelles de chaque chocolat, dans chaque boîte. Bien évidemment, le site comporte le bataclan habituel : tags, fonctions de recherche, avis des consommateurs, …

Si ça marche bien, on peut ensuite mettre en place un service d’échange entre personnes habitants à proximité. Deux machins dégeux à la noix de coco contre un succulent praliné au gianduja ? Ça marche !

Le concept est généralisable à tous ce qui se vend sous forme d’assortiment : yaourts aux fruits, sachets de thé, bonbons, bières, …

Pub’homme

toilet-paper-ad

Site web de contre-pouvoir à la publicité.

Au début, il y aurait juste des analyses et des recensements, pour mettre en lumière les techniques de fourbe régulièrement utilisées par la publicité :

  • hyperréalité
  • misandrie
  • sexualisation injustifiée
  • flatterie
  • association arbitraire avec une célébrité

Sérieusement, quelqu’un pourrait me dire ce qu’il y a de sexuel dans un putain de clacos ?

Ensuite, il serait envisageable de créer des structures de soutien aux victimes de la publicité. Par exemple :

  • Les techniciens Carglass. Il y a certainement beaucoup de clients qui se foutent de leur gueule, et les plus extrêmes ont peut-être même envie de leur cogner dessus.
  • Les gens qui s’appellent Mégane Renault ou Zoé Renault.
  • Les parents dont les enfants font des caprices à cause des jouets qu’ils voient dans les publicités.

(Parce que tout le monde n’est pas capable de se défendre aussi bien que les Leneuf).

Pour finir, on pourrait s’offrir quelques flash mobs. 500 personnes se retrouvant à une finale de Rolland-Garros pour balancer des Kinder Buenos à la gueule de Jo-Wilfried Tsonga, ça vous tente ?

Un jeu web avec une économie déflationniste

WoW_stats

Si vous lisez ce blog, vous connaissez déjà les bitcoins et les crypto-monnaies. L’une des raisons pour laquelle ce type de monnaie ne se démocratise pas, c’est qu’elles sont déflationnistes, un fonctionnement assez inhabituel. Un jeu web permettrait de le faire découvrir, d’expérimenter des situations, de détecter des comportements émergents, etc.

Pour le jeu en lui-même, pas la peine de se prendre la tête, il suffirait de reprendre un thème classique : gestion d’une ferme / d’un héros / d’un bar à gigolos … L’économie du jeu aurait les particularités suivantes :

  • La quantité totale d’argent ne change jamais. Au départ, tout est dans la caisse commune du jeu. Pour l’exemple, mettons qu’il y ait un million de pièce d’or.
  • Les premiers joueurs inscrits reçoivent 100 pièces d’or, les suivants 50, les suivants-suivants 5, etc. (Au passage, ça incite à s’inscrire le plus tôt possible). Au bout d’un moment, les nouveaux arrivés ne reçoivent rien. Ce n’est pas grave, ça ne les empêche pas de jouer, et de se constituer un capital de départ en produisant et vendant des objets de base aux autres joueurs.
  • Une pièce d’or est divisible à l’infini. Vous pouvez acheter une caisse de patates à 0.0000001 pièce d’or.
  • Pour que l’expérience soit complète, il faut que les joueurs puissent également faire du troc.

Ce dernier point comporte un risque, car les joueurs pourront décider d’utiliser une ressource de base pour leurs échanges, à la place de la monnaie déflationniste. Par exemple, ils définiront leurs prix en caisse de patates, plutôt qu’en pièces d’or. Ce risque est toutefois limité. Si la caisse de patate devient de fait la monnaie universelle, tous les joueurs chercheront à en fabriquer. Comme c’est une ressource de base, elle est très facile à produire, et elle deviendra donc une monnaie hautement inflationniste, en laquelle il sera difficile de faire confiance. Il y aura peut-être cohabitation de plusieurs monnaies. On ne sait pas, mais je pense que ça vaudrait le coup de tester.

YourCryptoCoins

crypto-coins

Un logiciel simple pour créer sa propre crypto-monnaie, avec pleins de paramètres à ajuster, histoire de tester s’il y a plus efficace que le bitcoin :

  • masse monétaire totale.
  • coût de transaction.
  • récompense par preuve de travail et/ou preuve de participation. Montant des récompenses.
  • difficulté de minage.
  • diminution automatique. (Tous les X jours, le solde de tous les comptes existants baissent de Y%, afin d’inciter les gens à dépenser leur argent)

Ça permettrait aux gens de se créer leur petite crypto-monnaie locale, ce qui est peut-être un peu plus fiable que des bouts de papier imprimés à l’arrache avec écrit “Soleil” dessus.

Un réseau de communication vraiment décentralisé.

semaphore

Le problème d’internet, c’est que les adresses IP sont attribuées par des autorités centrales. Et le support de communication (les fils téléphoniques et le spectre radio) est également sous contrôle central. Je ne sais pas trop comment y remédier, mais ça mérite réflexion.

On pourrait mettre des capteurs et des petites lumières clignotantes sur les toits des maisons, qui se transmettraient les informations entre eux. Concrètement, vous ne pouriez communiquer qu’avec vos voisins, mais des messages pourraient transiter de maison en maison. Et on utiliserait des uuid pour identifier chaque point du réseau. Avec un système de clé publique-machin-truc pour garantir l’identifiant de chaque point et éviter les usurpations d’identité.

Et pour les zones peu densément peuplée, on utiliserait des successions de petites lumières, ou des fils mais gérés de manière décentralisée.

Ce serait sûrement très lent et pas fiable (si vos voisins n’ont pas allumé leurs transmetteurs, vous ne pouvez plus communiquer). Mais ce serait “libre”. Et du coup, pas d’abonnement à payer, juste de l’électricité.

C’est vraiment brumeux comme idée, parce que j’y connais rien en bidouilleries réseau. Si d’autres gens ont des améliorations à proposer, qu’ils n’hésitent pas.

Poilatout

cousin_machin

Algorithme, qui, à partir d’une phrase donnée, renvoie le “poil au” correspondant.
Exemple :
“Quand l’imbécile montre la Lune”
-> “poil aux burnes”
“Le sage lui met un doigt”
-> “poil au foie”

Y’a plus qu’à plugger ça avec Siri, et votre smartphone vous permettra de spammer toutes vos conversations de “poil au”.

Si ça sert à rien, c’est que c’est indispensable.

Mi-tik

“Trouvez votre moitié”.

half_man_Andy_Gross

Vous êtes unijambiste de la jambe gauche. Vous vous inscrivez sur le site Mi-tik. Vous avez alors la possibilité d’être mis en relation avec des unijambistes de la jambe droite. Si vous trouvez quelqu’un qui vous correspond, vous obtenez 50% de réduction sur tous vos achats de chaussures.

Le site permet également de faire se rencontrer les manchots d’un bras, les borgnes, les “Van Gogh”, les hémiplégiques, …

HarDis (Harcèlement Distribué).

“Pensez dystopie globale, agissez dystopie locale”.

dented-car-chuck-norris

La loi française ne vous interdit pas de chier sur le palier de votre voisin, de rayer sa voiture ou de l’appeler à 2 heures du matin. Mais elle vous interdit de le faire de manière répétée. Ça s’appelle du harcèlement.

Le “réseau d’entraide HarDis” permet de s’affranchir de ce détail. Vous vous y inscrivez en déclarant un périmètre géographique d’action. Vous recevez ensuite des missions, vous demandant d’agir chez une personne-cible. Vous ne recevez jamais deux missions sur une même personne. À chaque fois que vous en effectuez une, vous envoyez une preuve de réalisation (photo, vidéo, …) et vous gagnez des points. Vous pouvez dépenser ces points pour créer des missions sur des gens que vous n’aimez pas.

L’identité et l’adresse des personnes-cibles est révélée le plus tard possible. Chaque compte a un indice de confiance, visible par tous, qui augmente lorsqu’on effectue une mission et diminue lorsqu’on en prend une et qu’on ne l’effectue pas. Le but étant de limiter les “espions” (des personnes qui ne veulent pas réaliser de missions, mais qui veulent juste surveiller si elles ne sont pas la cible de missions existantes).

Bien entendu, vous pouvez acheter des points, et bien entendu tous les outils d’anonymat sont disponibles : réseau Tor, crypto-monnaie, …

ADN-Fuck

“Là où y’a des gènes, y’a du plaisir”.

ensalada-de-pasta

La société ADN-Fuck rachète vos petits déchets corporels : salive, poils, sang, peaux mortes, urine, sperme… Elle les mélange avec ceux de centaines de personnes, et revend le tout sous forme de petit sachet.

Quelqu’un souhaitant commettre un acte illégal peut acheter l’un de ces sachet d’anonymisation, et le répandre sur les lieux de son acte. Bonne chance à la police scientifique pour retrouver l’ADN du coupable !

La société ADN-Fuck en elle-même ne commet rien d’illégal. Le commerce de poils de cul est, à priori, toujours autorisé dans la plupart des régions du globe.

RoboCraft

minecraft_robot

Un jeu vidéo comme Minecraft, mais avec des robots programmables (en python, évidemment !). On peut les faire miner, construire, explorer, transformer des ressources, etc.

Il y a déjà un add-on de Minecraft pour ça (ComputerCraft), mais c’est pas quelque chose de très officiel. Du coup, tout l’équilibrage du jeu est fait sans tenir compte de ComputerCraft. Un jeu conçu spécialement avec des robots, ce serait super chouette.

Ça rejoint le concept d’automatic-play, dont on parle ici ou là : http://gamestudies.org/1301/articles/depaoli_automatic_play

Et il faudrait une économie déflationniste dans le jeu. Et des robots à reconnaissance vocale qui disent “poil au cul”.

Multi-versus

multi_versus

Un jeu vidéo composé de mini-jeux, dans lequel deux joueurs ou plus s’affrontent, chacun avec un mini-jeux différent.

Par exemple, le joueur 1 (Tetris) affronte le joueur 2 (Puzzle Bobble). Lorsque le joueur 1 effectue des actions valorisantes, (détruire plusieurs lignes à la fois), il envoie de la difficulté au Puzzle Bobble du joueur 2 (des bulles noires impossible à détruire). Et vice-versa : si le joueur 2 détruit plus de 3 bulles d’un coup, il envoie des lignes de cochonnerie sur l’aire de Tetris du joueur 1.

Ce n’est faisable qu’avec des mini-jeux ou chacun joue sur son terrain (pas de Bomberman ni de Pong, par exemple), et ce serait une galère monumentale pour les équilibrer entre eux, mais ça serait vraiment fun.

Un format de fichier pour décrire des dessins animés.

Ce serait un format human-readable. C’est très important, car ça augmente la potentialité de bidouillage par n’importe qui, y compris des gamins de 8 ans.
Ça pourrait ressembler à ceci par exemple :

img_balle = http://s2.postimg.org/w709hznpx/balle.png
img_balle_ecrase = http://s18.postimg.org/hy41jochx/balle_ecrase.png
area = 147, 275
default_time = 5 ms

ball = Sprite(img_balle, 20, 0)
ball.move(0, 10)
ball.move(0, 10)
ball.move(0, 10)
ball.change_img(img_balle_ecrase)
ball.move(0, -10)
ball.move(0, -10)
ball.move(0, -10)

Et ça donnerait quelque chose de ce genre :

bounce_147

Et ensuite, on pourrait faire plein de trucs avec ce format de fichier :

  • des players web, des players desktop, des éditeurs, des extracteurs d’images,
  • des vidéos online (les images et les sons sont indiqués par des urls de téléchargement) et des vidéos stand-alone (tout est embarqué dans un .zip),
  • des options de sous-titres, de commentaires, d’audio-description, d’adaptation aux daltoniens et aux épileptiques,
  • des convertisseurs vers des fichiers vidéos classiques et vers du gif animé,
  • des méta-données pour les credits, la licence, le rating ESRB,
  • et bien d’autres choses encore !

Vous allez me dire : “mais il y a déjà plein de trucs qui font ça : le flash, les gifs animés, Blender…”

Oui, sauf que le flash c’est pas libre, les gifs c’est pas optimisé et c’est super compliqué à reprendre et à bidouiller, et Blender, il faut des mois de pratique avant de savoir faire quelque chose de correct.

Ce format de fichier permettrait de créer rapidement des petits trucs à l’arrache, des cartes de vœux, des memes animés, etc. Et comme c’est du texte, c’est versionable et éditable collaborativement.

Githubiser pleins de trucs.

github-octocat

Alors voilà, vous êtes un musicien et vous faites un solo de flûte à bec comme ça pour déconner. Vous le mettez sur gitsound. Quelqu’un d’autre arrive et ajoute une ligne de basse. Un autre y met quelques paroles. Un autre refait votre air initial avec une guitare électrique. Un autre reprend le tout en accéléré. Un autre y ajoute un “Cher effect” et colle un flow de rap par dessus. Et ainsi de suite.

Ou alors, vous êtes un modéliseur 3D et vous commencez à créer un arbre géant. Quelqu’un arrive et ajoute des mini-branches pour lui donner un air plus détaillé. Un autre met des textures plus belles pour les feuilles. Un autre creuse un trou à l’intérieur. Un autre le recopie en 1000 exemplaires sur un quadrillage pour en faire un décor de clip de Mark Gormley. Et ainsi de suite.

Il y a plein d’autres trucs qu’on pourrait githubiser afin de faciliter la création collaborative : les images (vectorielles ou pas), les recettes de cuisine, les règles de jeux de société, les dessins animés, les positions du kama-sutra, … Et pour certains médias, le github de base, qui ne permet de traiter que du texte, ne suffit pas.

Un Tolkien de la culture africaine

blackfoot-medicine-man-right

Tolkien connaissait toutes les légendes de son pays et d’ailleurs. Il a défini la plupart des éléments de l’heroic fantasy. Sans lui, pas de Donjons et Dragons, de World of Warcraft, ou de Harry Potter. Maintenant, l’heroic fantasy vole de ses propres ailes et emprunte des éléments à d’autres cultures : momies égyptiennes, ninjas asiatiques, doppelgängers teutons, mind flayer lovecraftien, …

Mais à part les zombis, on trouve très peu de choses empruntés à la mythologie africaine. C’est vraiment dommage, car avec le foisonnement culturel de ce continent, on pourrait créer des mondes imaginaires de dingue, peuplés de créatures étranges et de magie aux règles complexes, très différent de l’heroic fantasy.

Il faudrait une personne qui connaisse tous ces trucs (l’animisme, le vaudou, les totems, les esprits, …) et qui s’en inspire pour écrire une chiée de bouquins. Ensuite, les rôlistes, les gamers et J.K. Rowling feront le reste.

Voilà, ce sera tout pour le moment. Phosphorez mes braves, phosphorez !! Et si l’une de ces idées existe déjà réellement, prévenez-moi, ça m’intéresse.

]]>
http://sametmax.com/des-idees-que-jaurais-jamais-le-temps-de-faire/feed/ 31 12601
Télécharger les vidéos de Youtube http://sametmax.com/telecharger-les-videos-de-youtube/ http://sametmax.com/telecharger-les-videos-de-youtube/#comments Wed, 02 Oct 2013 07:51:58 +0000 http://sametmax.com/?p=7251

Ceci est un post invité de Recher posté sous licence creative common 3.0 unported.

– Assistance informatique, bonjour.

– Salut les moines bouddhistes. Comment je fais pour aller sur Youtube ? Votre stupide filtre à puceaux me bloque l’accès !

– C’est lié à la politique de l’entreprise. Le site est totalement interdit.

– Mais bordel, c’est la pause de midi ! Je suis toute seule dans mon service, et je suis excitée ! Pas un seul stagiaire à me mettre sous la dent ! J’ai besoin de mes vidéos pornos ! Et quand je dis “besoin”, c’est VRAIMENT besoin !

– Veuillez m’excuser Madame, mais je ne peux rien pour vous.

– J’ai la patcholle qui palpite à la vitesse d’une levrette au galop ! C’est urgent !

– La patcholle ? Mais enfin Madame, ce mot n’existe même pas !

– Le mot n’existe peut-être pas, mais ma patcholle, elle, elle existe ! Et elle est pas loin de la combustion spontanée !

– La seule solution serait que vous achetiez des DVD, et que vous les rameniez à votre bureau. On ne contrôle que ce que vous faites sur internet, pas ce que vous visionnez en local.

– Merci pour le conseil, mon p’tit chou, j’ai tout ce qu’il faut à la maison. Mais là, c’est d’une vidéo spécifique dont j’ai envie. Celle avec le nain et les ballons de baudruche. Et elle n’est que sur Youtube !

– Vous pouvez la télécharger. Changez l’URL, ajoutez les lettres “ss” devant le mot “youtube”, sélectionnez ensuite la qualité parmi celles disponibles, et vous récupérerez le fichier sur votre disque. Par exemple : http://www.ssyoutube.com/watch?v=uSGnmCTkIfE. Avec un peu de chance, l’accès par la connexion de l’entreprise n’est même pas bloqué.

– Attendez j’essaye. Je connais l’adresse de ma vidéo par cœur. … Oh putain, ça marche ! Et ça passe même le filtre à puceaux de Youtube ! Ooouiiiii !! Va y avoir de la cyprine plein les murs !

– Cela m’a fait plaisir d’avoir pu vous aider, Madame.

– De même. Dites, pendant que ça télécharge, vous voulez pas venir me rendre visite ? On se trouverait bien quelques corpuscules de Krause avec lesquels s’occuper.

– Merci Madame, mais ça ne m’intéresse pas.

– Je vous propose du sexe gratuit et vous n’en voulez pas ? Ah d’accord, vous êtes homosexuel. J’aurais dû m’en douter, à votre petite voix fluette. De toutes façons, ils sont tous pédés dans l’informatique.

– Au contraire Madame, je suis hétérosexuelle. En revanche, je suis une femme. Bon après-midi à vous.

Sofia the Rose en secrétaire sexy

]]>
http://sametmax.com/telecharger-les-videos-de-youtube/feed/ 11 7251
Comment le Revenu de Base Inconditionnel pourrait maximiser le bonheur. http://sametmax.com/comment-le-revenu-de-base-inconditionnel-pourrait-maximiser-le-bonheur/ http://sametmax.com/comment-le-revenu-de-base-inconditionnel-pourrait-maximiser-le-bonheur/#comments Fri, 10 May 2013 11:31:50 +0000 http://sametmax.com/?p=6028

Ceci est un post invité de Recher posté sous licence creative common 3.0 unported.

Recher est un des premiers lecteurs (et soutient) du blog, donc nous avons choisi de le laisser exprimer des idées qui lui sont chères. Notez que ce n’est PAS la marque d’un changement de ligne éditoriale du blog et que ce n’est PAS l’annonce de plus d’articles sur des thèmes politiques sur Sam et Max.

Ceci dit, un de temps en temps ne fait pas de mal. Ne vous battez pas trop en comments :-)

Quelques faits amusants concernant les humains

La viande, c’est la force

Lorsque les hommes préhistoriques tuaient une grosse bestiole, ils ne pouvaient ni manger toute la viande d’un coup, ni la conserver. La meilleure solution qu’ils ont trouvé a été de donner cette viande à d’autres hommes préhistoriques, qui se sentaient alors redevable, et qui partageraient la viande de leurs chasses futures.

Le placement bancaire de l’homme préhistorique, c’était l’estomac des autres.

D’ailleurs, selon de nombreux scientifiques, ce qui a fait que l’homo sapiens soit devenu ce que nous sommes aujourd’hui, c’est que pour survivre, ils s’échangeaient leur savoir. Sans cela, on aurait certainement très vite disparu. Comparé aux autres espèces, l’homo sapiens est une pauvre lopette qui n’a rien pour lui.

Source approximative (webarchivée, et qui elle-même ne cite pas ses sources)

Le cours du tigre à dents de sabre a chuté de 3 points. Groumf !

Une expérience un peu glauque du 13ème siècle

Frédéric 2, Suprême Tôlier du Saint-Empire romain germanique, voulait savoir quelle serait la langue que parlerait naturellement un homme n’ayant pas reçu d’influences extérieures. Il prit plusieurs bébés, et demanda à des nourrices de s’en occuper avec beaucoup de soin, mais sans jamais leur parler. Il s’attendait à ce qu’ils finissent par parler grec ou latin.

Ça a méchamment échoué. Les bébés ont dépéris et ils sont tous morts.

Géant vert, nain jaune, etc.

Il y a une expression à la mode, qui dit : “Nous sommes des nains sur des épaules de géants”. Les géants représentent nos ancêtres, qui ont accumulé des connaissances et construit des trucs pour que les générations suivantes vivent mieux. Les nains représentent les humains actuels, qui contribuent eux aussi à améliorer la condition humaine, pas autant que les géants, mais un peu quand même. L’ensemble géant + nain étant plus haut que le géant tout seul.

Les pensées d’un philosophe-généticien-mathématicien-humaniste

Albert Jacquard dit : “je suis les liens que je tisse avec d’autres”.

C’est une phrase bizarre. Ce n’est pas : “les liens que je tisse avec d’autres révèlent ma nature profonde”. C’est : “ma nature profonde, ce sont les liens”.

Ça veut dire qu’on construit sa personnalité par les relations qu’on a avec les autres. Ça ressemble à une idée hippie-new-age-cucul-la-praline, mais en fait non. Si on a des relations de merde et qu’on insulte tous le monde, on se construit une personnalité de merde. On fait ce qu’on veut de soi-même.

C'est lui Albert Jacquard. Il peut créer un seau rempli de chromosomes par la seule force de sa volonté.

Le fonctionnement de l’humanité.

À partir de ces quelques faits amusants, il me semble être possible de déduire deux principes globaux :

Les humains sont interdépendants avec leurs contemporains, ainsi qu’avec les générations passées et futures.

Cette interdépendance est inévitable. Vous n’avez pas le choix, à moins d’être un ermite habitant une grotte et chassant pour se nourrir. Et si vous décidez de vivre comme ça, surtout, ne partagez pas votre viande de mammouth, vous reprendriez votre interdépendance.

Même quelqu’un de très riche est interdépendant, car il a besoin d’un pool d’humain “de bonne qualité”, à qui il pourra acheter des biens et services de bonnes qualités : un bon comptable, un bon cuisinier, un bon chauffeur, un bon constructeur de piscine, un bon médecin, un bon chirurgien esthétique… Ce riche quelqu’un ne pourra pas former son pool d’humain par lui-même. Ça nécessite beaucoup de temps, plus que le temps d’une seule vie, fût-elle de riche.

Interdépendance des gens riches entre eux-même. Source : http://www.cairn.info/revue-societes-contemporaines-2007-4-page-105.htm (tl;dnr)

Plus on développe des liens de bonne qualité avec les autres, plus on est heureux.

Voici un graphique exprimant le bonheur d’une personne en fonction de son argent

Des courbes comme ça mériteraient clairement un petit coup de xkcdify.

Et un autre exprimant le bonheur d’une personne en fonction de la qualité et de la quantité de liens qu’elle a tissé avec d’autres.

Mais j'avais la flemme et je sais pas me servir de xkcdify, désolé !

Le bonheur total d’une personne étant, à peu de choses près, la somme de ces deux bonheurs.

Cette théorie rejoint plus ou moins celle de la pyramide de Maslow. Sauf que le grand Wikipedia dit que des tas de gens ont invalidé la pyramide de Maslow. Je vais donc pas trop m’attarder dessus, et faire comme si on n’était pas au courant. (Un peu de mauvaise foi, ça aide toujours les argumentations).

À partir de ces 2 graphiques, mon conseil en tant que coach du sens de la vie, est le suivant :

Si vous êtes vraiment pauvres, essayez d’abord de récupérez de l’argent, plutôt que de vous faire des amis. Ça vous rendra heureux plus vite. Une fois que vous avez atteint un seuil de revenu suffisamment satisfaisant et régulier, ce sera devenu moins rentable, en terme de bonheur, de chercher à gagner encore plus. À partir de là, essayez de vous faire des amis et de créer des liens.

Au passage, cela me permet de rappeler qu’il faut conserver la neutralité d’internet, car c’est une formidable machine à fabriquer des liens.

Et au passage bis, je ne pense pas que l’être humain soit “naturellement bon”. Les concepts “bon” et “mauvais” me semblent trop compliqués pour qu’ils puissent être implémentés dans la nature.

J'ai hésité entre ça et une image de South Park épisode 10 saison 1. Et je me suis dit que South Park, c'était tellement conventionnel.

En fait, l’humain cherche à maximiser son bonheur personnel, sans forcément se soucier des autres. Mais en plus de ça, une bonne partie des humains a pris conscience du graphique “liens tissés -> bonheur”, ce qui va les amener à vouloir développer des liens de bonne qualité avec les autres : rendre service, discuter, échanger des idées, … Ça donne l’impression qu’ils sont naturellement bon, alors qu’en fait, ils cherchent juste à être heureux eux-même, le plus efficacement possible.

Toute la question est de savoir comment faire prendre conscience aux humains de la relation entre le bonheur et les liens tissés. Je n’ai pas de réponse précise (éducation ? liens initiaux ?)

Où veux-je donc en venir ?

Il vaut mieux pour vous-même que les humains proches de vous soient pas trop cons, pas trop pauvres et un minimum heureux. Ceci pour 2 raisons :

  • Afin de maximiser votre bonheur personnel, vous devez développer des liens de bonne qualité. Or c’est plus facile à faire avec des gens “de bonne qualité”.
  • Dans “interdépendance inévitable” il y a “dépendance inévitable”. C’est moins inquiétant d’être dépendant de gens de bonne qualité, plutôt que d’un ramassis de crève-la-faim dépressifs qui ne savent rien faire.

Il existe un moyen simple pour s’assurer que tous les humains autour de vous soient un minimum heureux, et aient la possibilité matérielle d’être d’une qualité minimale : le graphique “argent -> bonheur”.

Si on s’assure que tout le monde a la possibilité de s’avancer un peu dans ce graphique, afin d’arriver à peu près au point “Appartement”, on augmentera énormément le bonheur de beaucoup de gens, à peu de frais.

Si on s’assure que tout le mode peut s’avancer encore plus dans le graphique (par exemple, jusqu’au point “Rolex”), ce sera moins rentable. Il faudrait beaucoup plus d’argent, pour une augmentation de bonheur plutôt faible. Autant donc rester dans des sommes raisonnables.

L’idée qui en résulte s’appelle le Revenu de Base Inconditionnel.

J'ai jamais compris comment Kurt Cobain pouvait chanter sous l'eau.

Explication du Revenu de Base Inconditionnel en un paragraphe

Cela consiste à donner la même somme d’argent, tous les mois, à toutes les personnes d’un pays ou d’une région. Ce Revenu continue d’être perçu même lorsqu’on commence à travailler, et quel que soit le type de contrat de travail. La somme donnée est calculée de façon à ce que chaque personne puisse vivre “dignement”, c’est à dire : bouffer, se loger et éventuellement acquérir certains biens culturels de base.

Cette idée (pas si nouvelle que ça) est actuellement en train de susciter des réflexions ici et là. C’est alors que des gens se sont dit que ce serait bien de lancer une Initiative Citoyenne Européenne, pour également faire réflexionner les gens qui nous gouvernent.

Explication de l’Initiative Citoyenne Européenne (ICE) en un paragraphe, avec mes propres termes, donc simplifiée à outrance

Une ICE est créée par un petit groupe de gens, qui demandent que soit mis en place un “truc dans la loi” (Ça peut être un peu tout, mais pas complètement n’importe quoi). Les citoyens de l’Union Européenne qui sont d’accord avec le truc en question signent une pétition. Si au bout d’un an, un million de signature est récupéré, la Commission Européenne est obligée de venir écouter le groupe initiateur de l’ICE, de réfléchir au truc et de donner un avis. La Commission Européenne peut répondre “on ne fera pas votre truc, GTFO LOL”, mais cela doit être accompagné d’arguments détaillés.

C’est là où je voulais en venir. Je vous invite à signer l’ICE pour le Revenu de Base Inconditionnel, afin de réfléchir à cette technique d’optimisation du bonheur humain. Pour en savoir plus, pour des infos pratiques et concrètes, et pour finalement signer en ligne, ça se passe par ici : http://revenudebase.info/initiative-citoyenne-europeenne/

Si vous pensez que c’est une idée de merde parce que <pleins de raisons>.

Le Revenu de Base Inconditionnel modifierait en profondeur notre façon de nous comporter en société, en modifiant notre rapport à l’argent, au travail et aux autres. C’est pourquoi, il suscite beaucoup de réactions, parfois assez fortes, de refus ou d’acceptation.

Les raisons de refuser cette idée sont assez diverses, mais on retombe souvent sur les mêmes. Des gens les ont alors rassemblées, et y ont opposés des arguments pour refuser ce refus. Je vous laisse quelques liens à ce sujet. Rassurez-vous, le propos y est bien plus concret que la réflexion nuagesque que j’ai faite en début d’article.

“Les chômeurs vont jouer à la Playstation”
http://revenudebase.info/2013/04/revenu-base-pas-outil-lutte-contre-chomage/

“C’est une idée libérale / de communiste”
“Cela poussera les gens à l’oisiveté”
“Plus personne ne voudra effectuer les tâches ingrates”
“Le revenu de base va provoquer de l’inflation”
“C’est une idée utopiste”
“C’est impossible à financer”
“L’état est déjà très généreux en France, ça ne va rien changer”
“L’immigration va encore plus augmenter”
“La société n’est pas prête, il faut d’abord réformer le système”
http://www.tetedequenelle.fr/2011/04/mauvaises-raisons-revenu-de-vie/

It prints money !

Si vous pensez toujours que c’est une idée de merde.

C’est votre droit. Et si ça se trouve, c’est vous qui avez raison.

Mais même dans ce cas, je vous invite à signer l’ICE. Celle-ci n’oblige pas l’Europe à instaurer le Revenu de Base. Elle oblige à réfléchir à l’idée du Revenu de Base.

Si c’est une idée de merde, les gens de la Commission Européenne auront tôt fait de s’en apercevoir, car ils sont certainement plus calés que moi en économie, géopolitique, psychohistoire et autres. Ils pourront alors expliquer à tout le monde, et avec des arguments valables, en quoi c’est de la merde. Si c’est le cas, je promets de ne plus embêter personne avec cette idée. Une toute petite signature en échange de votre tranquilité future, ça vaut le coup non ?

Le bonheur vaincra !

]]>
http://sametmax.com/comment-le-revenu-de-base-inconditionnel-pourrait-maximiser-le-bonheur/feed/ 42 6028
Union d’un ensemble d’intervalles http://sametmax.com/union-dun-ensemble-dintervalles/ http://sametmax.com/union-dun-ensemble-dintervalles/#comments Sun, 17 Feb 2013 06:42:43 +0000 http://sametmax.com/?p=4572

Ceci est un post invité de Réchèr posté sous licence creative common 3.0 unported.

Kikoo amis matheux ou pas. Aujourd’hui, on va se faire un petit algo de derrière les fagots. Vous n’en aurez peut-être jamais besoin dans le monde réel, mais, qui a dit qu’on allait se contenter uniquement de ce dont on a besoin ? De plus, je présenterais, à la fin, une astuce générique d’algorithmiciens.

Pré-requis

  • Connaître très vaguement la notion des O(n²), O(truc), … qui définissent le temps d’exécution d’un algorithme en fonction de la quantité de données à traiter. (Si ça vous parle pas c’est pas grave).
  • Savoir que le pluriel d’intervalle n’est pas “intervaux”.

Petite précision : pour définir des intervalles d’entiers, j’emploierais la convention pythonienne : le dernier élément n’est pas inclus. C’est à dire que [2, 7] correspond à 5 éléments : 2, 3, 4, 5, 6.

Énoncé

Soit une liste de couple de nombres, représentant des intervalles. Ils sont tout en vrac, y’en a qui se chevauchent, d’autres qui s’inclusent, etc. Bref, l’ensemble fait penser à une partouse animale multi-espèces.

exemple : [ [2, 7], [3, 7], [1, 5], [9, 10], [8, 9] ]
Les crochets d'intervalles ont une tronche bizarre. C'est pour bien montrer que le dernier élément n'est pas inclus.

Vous voulez une méthode pour rassembler tout ça, et obtenir une liste d’intervalles, triée, sans chevauchement, correspondant à la fusion de tous les intervalles de départ. En maths, on appelle cette opération une union. En partouse animale multi-espèces, on appelle aussi ça une union, mais ce n’est pas le sujet.

résultat souhaité : [ [1, 7], [8, 10] ]
Toujours cet éternel problème de nombre de poteaux versus nombre d'intervalles. Je suis sûr que si on était dans un univers non-eucliden on serait pas emmerdé avec ce genre de détail à la con.

Solutions auxquelles on pense en premier

Le bourrin pas-à-pas

On récupère le début d’intervalle le plus à gauche, et la fin la plus à droite. On boucle entre ces deux valeurs. À chaque itération, on effectue le traitement suivant :

  • Vérifier si la valeur courante est dans au moins un intervalle.
  • Si oui, et que juste avant on était dans aucun intervalle, alors on marque cette valeur comme un début d’intervalle.
  • Si non, et que juste avant on était dans au moins un intervalle, alors on marque cette valeur comme une fin d’intervalle.

Désavantages

Si, au départ, on a deux intervalles très éloignés, par exemple [0, 2] et [1000000, 1000002] on va faire une boucle de 1000002 itérations. Pour traiter 2 intervalles, c’est un peu lourd.

Ça ne marche qu’avec des entiers. Si on a des intervalles de réels, on itère comment ? En avançant de 0.0000000001 en 0.0000000001 ? Même problème avec des intervalles de date-heure.

Le bourrin cumulatif

On crée une liste géante de booléens, tous à False, qui s’étend du premier début d’intervalle à la fin du dernier. Chaque booléen indiquera si le nombre correspondant se trouve dans au moins un intervalle. On met les bons booléens à True en parcourant les intervalles de la liste initiale. Puis, on construit la liste finale d’intervalles, en se basant sur les booléens.

Désavantages

Si on a en entrée un million de fois l’intervalle [10, 210], on va mettre un million de fois à True la même suite de 200 booléens. 200 millions d’opérations pour ressortir un unique intervalle [10, 210].

Même problème que précédemment. Ça ne marche qu’avec des nombres entiers.

Du bourrin et du cumulatif : serait-ce l'occasion d'invoquer une grand-mère à moustache ?

L’enfileur de perles

On a d’un côté la liste finale des intervalles (initialisée à vide), et de l’autre, la liste initiale, en bordel. On passe les intervalles d’une liste à l’autre, un par un, en testant les cas suivants :

  • Le début et la fin de l’intervalle en cours n’est dans aucun intervalle final -> ça fait un nouvel intervalle final.
  • Le début est dans un intervalle final, mais pas la fin -> ça rallonge l’interval final existant.
  • La fin est dans un intervalle final, mais pas le début -> ça rallonge l’intervalle final existant, mais par l’autre côté.
  • La fin et le début sont dans le même intervalle final -> l’intervalle en cours ne sert à rien.
  • La fin et le début sont dans deux intervalles finaux différents. -> il faut fusionner les deux intervalles finaux.

Et en plus de tout ça, il faut également tester s’il n’y a pas des intervalles finaux entièrement inclus dans l’intervalle en cours. Auquel cas, ils ne servent plus à rien, et doivent être enlevé de la liste.

Désavantages

Une bonne grosse prise de tête à coder tous les cas possibles, sans rien oublier, sans bug.

Le fait de chercher si un nombre se trouve dans une liste d’intervalles, fut-elle triée, est une opération qui prend un certain temps. Ça peut s’optimiser avec de la dichotomie ou des trucs du genre, mais quand même.

Par contre, cette algo marche avec des nombres réels et des date-heure. Youpi.

Je pige même pas comment ce jouet est censé fonctionner. Faut mettre les perles dans le trou de la machine ? Comment le trou de perle se met en face du fil ? Est-ce que ça serait pas encore plus galère qu'à la main ?

Et si on arrêtait les conneries ?

Dans ces premières solutions, on considère les intervalles comme des objets immuables. Il faut en traiter un entièrement avant de passer au suivant. Mais on peut aussi les voir comme deux événements distincts (un début et une fin), que l’on peut dissocier totalement, et traiter dans leur ordre d’arrivée. On ne sera plus capable de retrouver quel début correspond à quelle fin, mais ça on s’en fout, y’a rien qui ressemble plus à un intervalle qu’un autre intervalle.

Imaginez un petit bonhomme (ou une petite bonne femme, respectons la parité). Au départ, il est au niveau du sol. Il avance vers la droite. Quand il rencontre un début d’intervalle, il monte sur un mur d’un étage. Quand il rencontre une fin, il descend d’un étage. Il peut être sur plusieurs étages superposés. Au fur et à mesure qu’il se déplace, on note les endroits où il se retrouve sur le sol. Ces endroits correspondent à des zones sans aucun intervalle.

Je vous laisse retrouver de quel jeu vidéo est tiré ce screenshot. Je l'avais beaucoup aimé. Je trouvais l'univers très onirique, et très "compte de fée mais pas cucul, parce que y'a quand même dedans des aventures qui poutrent de la rascasse particulaire avec un chandelier dans la véranda."

Mes parents n'arrêtaient pas de me dire que mes jeux se ressemblaient tous. Puis ils m'emmenaient visiter des églises et des châteaux qui se ressemblaient tous. Bizarre...

Le code

def tri_bonhomme_sur_un_mur(list_intervalle_en_bordel):
    """ Effectue une union de tous les intervalles indiqués en paramètre.
    
    Données d'entrée : une liste de liste de deux éléments, représentant
    des intervalles.
     - Le type des éléments n'est pas imposé. Il faut juste qu'on puisse 
       les ordonner et les trier. 
     - Dans chaque liste de deux éléments, le premier doit être plus 
       petit que le second. 
    La fonction ne vérifie pas ces contraintes. Si elles ne sont pas 
    respectées, le comportement est indéterminé. Ça peut planter, 
    ça peut renvoyer un résultat faux sans avertissement, etc.
    
    Sortie : une liste de liste de deux éléments, unionnisée et triée
    comme il faut.
    """
    # On extrait tous les débuts d'intervalles, et toutes les fins.
    list_debut = [ interv[0] for interv in list_intervalle_en_bordel ]
    list_fin = [ interv[1] for interv in list_intervalle_en_bordel ]
    # On les trie, pour pouvoir les traiter de gauche à droite.
    list_debut.sort()
    list_fin.sort()
    # Cette liste contiendra les intervalles unionnisés et triés.
    list_intervalle_final = []
    # indique le nombre d'invervalle superposés dans lesquels on se trouve
    # actuellement. (C'est à dire : le nombre d'étages sur lequel
    # marche le bonhomme).
    nb_superposition = 0
    # Lorsqu'on est dans un ou plusieurs intervalles superposés, on doit
    # se souvenir à quelle position on est entré dans le premier.
    # Cela permettra de créer l'intervalle final, lorsqu'on sera 
    # complètement sorti de la superposition en cours.
    debut_intervalle_courant = 0
    
    # C'est parti ! Le petit bonhomme avance. On lui fait traiter les
    # événements d'entrée et de sortie d'intervalle au fur et à mesure 
    # qu'ils arrivent.
    while list_debut:
        # Le premier élément de list_debut, c'est le premier début 
        # d'intervalle qu'on rencontrera. Le premier élément de list_fin,
        # c'est la première fin d'intervalle qu'on rencontrera. On 
        # détermine, parmi ces deux événements, lequel on rencontrera en 
        # tout premier.
        #
        # La fonction cmp renvoie -1, 0, ou 1, selon la comparaison 
        # effectuée entre les deux valeurs passées en paramètre.
        # Faire un petit help(cmp) pour connaître les détails.
        ordre_debut_fin = cmp(list_debut[0], list_fin[0])
        if ordre_debut_fin == -1:
            # L'événement rencontré est un début d'intervalle.
            # On enlève l'événement de la liste, puisqu'on va le traiter,
            # là, tout de suite.
            pos_debut = list_debut.pop(0)
            if nb_superposition == 0:
                # On était dans aucun intervalle, et on vient d'en 
                # rencontrer un. Dans la liste finale d'intervalles, 
                # ça va donc compter comme un début. On retient 
                # cette info.
                debut_intervalle_courant = pos_debut
            # Dans tous les cas, on ajoute une superposition d'intervalle
            # (le bonhomme monte d'un étage).
            nb_superposition += 1
        elif ordre_debut_fin == +1:
            # L'événement rencontré est une fin d'intervalle.
            # On l'enlève de la liste.
            pos_fin = list_fin.pop(0)
            # On enlève une superposition d'intervalle.
            nb_superposition -= 1
            if nb_superposition == 0:
                # Après avoir enlevé la superposition, on se retrouve
                # avec 0 intervalle superposé. 
                # (Le bonhomme est redescendu jusqu'au niveau du sol).
                # Il faut donc enregistrer ça comme une fin d'intervalle 
                # final. Tant qu'on y est, on crée tout de suite ce nouvel
                # intervalle final et on le met dans la liste.
                nouvel_intervalle = (debut_intervalle_courant, pos_fin)
                list_intervalle_final.append(nouvel_intervalle)
        else:
            # On rencontre à la fois un début et une fin d'intervalle.
            # Rien de spécial à faire. Faut juste virer les 2 événements 
            # traités de leur liste respectives.
            list_debut.pop(0)
            list_fin.pop(0)
    
        # Durant toute cette boucle, la variable nb_superposition augmente
        # et diminue. Mais elle n'est jamais censée devenir négative.
        # Si ça arrive, c'est que les données d'entrées sont mal foutues.
        # On entre dans un cas d'indétermination. 
    
    # Arrivé à la fin de la boucle, il peut rester, ou pas des éléments
    # dans list_fin. Ce qui est sûr, c'est que list_debut se vide
    # avant list_fin. Si ce n'est pas le cas, c'est encore un cas
    # d'indétermination.
    
    if list_fin:
        # On a passé tous les débuts d'intervalle, mais il reste des
        # fins. Ça veut dire qu'on est encore dans un ou plusieurs
        # intervalles. On devrait normalement avoir :
        # len(list_fin) == nb_superposition. Si c'est pas le cas, c'est
        # un cas d'indétermination.
        #
        # On pourrait traiter les événements de fin d'intervalle un par un,
        # et diminuer progressivement nb_superposition. Mais on s'en fout,
        # c'est pas nécessaire. On prend juste la fin d'intervalle qui 
        # supprimera la dernière superposition (c'est à dire la dernière
        # fin d'intervalle), et on construit un dernier intervalle final
        # avec ça.
        pos_fin = list_fin[-1]
        nouvel_intervalle = (debut_intervalle_courant, pos_fin)
        list_intervalle_final.append(nouvel_intervalle)
    
    return list_intervalle_final

Les avantages (parce que y’a aucun désavantages)

Ça marche avec des réels, des dates, et de manière générale, tout ce qu’on peut trier.

>>>tri_bonhomme_sur_un_mur([ [2, 7], [3, 7], [1, 5], [9, 10], [8, 9] ])
[(1, 7), (8, 10)]

# Testez pas ça chez vous ! Ça prend trois plombes ! Mettez juste 1000.
>>>tri_bonhomme_sur_un_mur( [ [10, 210], ] * 1000000 )
[(10, 210)]

# Voyons voir ce que ça donne avec des réels 
# (dont certains sont négatifs, tant qu'à faire).
>>>tri_bonhomme_sur_un_mur([ 
    [-7.2, -6.9], [-8.4, -5.3], [-10.5, -5.25], 
    [-1.7, 0.01], [0.0, 4.0], 
    [12.125, 13.9, ], [13.9, 15.0]])
[(-10.5, -5.25), (-1.7, 4.0), (12.125, 15.0)]    
    
# et avec des dates
>>>from datetime import datetime
>>>tri_bonhomme_sur_un_mur([
    [datetime(2012, 12, 21, 16, 54), 
     datetime(2013, 02, 16, 12, 59)], 
    [datetime(2013, 02, 14, 2, 0), 
     datetime(2069, 01, 01, 13, 37), ] ] )
[(datetime.datetime(2012, 12, 21, 16, 54),
  datetime.datetime(2069, 1, 1, 13, 37))]                           

En ajoutant à peine 2-3 lignes de code à la fonction, on peut récupérer le nombre maximal d’intervalles superposés.

En re-ajoutant quelques autres lignes, on peut récupérer les zones dans lesquelles ce maximum est atteint. Ce qui pourrait servir pour effectuer l’opération mathématique d’intersection. (Je vous laisse chercher ça par vous mêmes).

L’algorithme est principalement constitué d’une bi-boucle, c’est à dire une boucle unique, qui avance dans deux listes différentes (je viens d’inventer ce terme, ne m’embêtez pas). C’est encore plus simple que deux boucles imbriquées. Le nombre d’itérations à effectuer est égal au nombre d’intervalle multiplié par deux, c’est tout. Dans tous les cas limites présentés ci-dessus, ça fait une solution acceptable, demandant un temps d’exécution peu pharaonique.

Exemple de deux bi-boucles imbriquées au niveau de la vis. Cette image vous a été offerte par les Scissor Sisters.

Mais ou est passé la complexité ?

Les premières solutions avaient l’air de demander énormément de temps d’exécution, surtout avec beaucoup d’intervalles en entrée. Ça ne semble pas être le cas pour la solution du “bonhomme sur un mur”. Pourtant, la complexité d’une tâche, ça ne disparaît pas comme par magie. Y’aurait-il une entourloupe quelque part ?

Il y en a une. Ce sont les deux opérations de tri effectuées au début de la fonction. Un tri, ce n’est pas anodin, et son temps d’exécution peut augmenter très beaucoup et très vite. La complexité n’a pas disparue, on n’a fait que la déplacer vers des tris. Alors finalement, ma solution n’est pas si bien que ça ?

Eh bien si. Parce que le tri, même s’il reste coûteux en temps et en ressource, est un problème archi-connu, archi-réglé, et archi-optimisé. Le python, comme beaucoup d’autres langages, profite pleinement du travail réalisé par des centaines de matheux algorithmologues, qui se sont masturbés l’esprit sur des centaines de méthodes de tri différentes.

Y'a des fois, on sait que l'image dont on a besoin ne sera pas trouvable sur l'internet. Alors on est obligé de la créer soi-même. (Mais je me suis fait aider).

Photo prise dans le bureau d'un chercheur en algorithmologie.

C’est ça l’astuce générique dont je vous parlais au début. Face à un nouveau problème, le matheux sort son zguègue tente de trouver des équivalents à un ou plusieurs problèmes connus, que lui et ses amis matheux ont déjà réglés. C’est souvent bien plus simple que de tenter de régler le problème directement, en partant de rien.

“Un nain éjacule bien plus loin lorsqu’il est perché sur les épaules d’un géant.” Et pour respecter la parité, j’ajouterais qu’une naine femme-fontainise bien plus loin lorqu’elle est perchée sur les épaules d’une géante.

]]>
http://sametmax.com/union-dun-ensemble-dintervalles/feed/ 15 4572
Faire des enums en python http://sametmax.com/faire-des-enums-en-python/ http://sametmax.com/faire-des-enums-en-python/#comments Wed, 19 Dec 2012 17:41:10 +0000 http://sametmax.com/?p=3741

Ceci est un post invité de Réchèr posté sous licence creative common 3.0 unported.

“Moi, je viens du C++”

Voilà un propos qui fait classe. Ça donne un air de vieux de la vieille, à qui on ne la fait pas, et qui connaît des langages que c’est pas des langages de taffioles. “De mon temps, fallait savoir ce qu’on faisait, sinon tout plantait. On ciselait notre code à la main dans des blocs de granit. Vous les gosses de maintenant, vous connaissez plus rien. Eh ! Sale jeune, au lieu d’importer des lib de feignasses, vient donc me changer ma poche à urine.

Ça aurait été encore plus classe de dire que je viens de l’Assembleur, mais je suis pas assez vieux pour ça. Et de toutes façons, en vrai, je viens du Pascal. Bref, passons.

Tout ça pour dire que dans le C++, il existe quelque chose que j’avais trouvé bien sympa : les enums.

Comment ça marche ?

Un enum est un type de variables ayant un domaine de valeur fixe et prédéfini, que l’on spécifie lors de la déclaration du type.

typedef enum
{
     Pique,
     Coeur,
     Trefle,
     Carreau
} ECouleursCartes;

Ensuite, on peut déclarer une variable de ce type, et lui affecter l’une des valeurs autorisées.

ECouleursCartes vMaCouleurCarte;
vMaCouleurCarte = Trefle;

Concrètement, chaque valeur correspond à un entier. Le compilateur fait les correspondances tout seul comme un grand.

À quoi ça sert ?

À avoir du code plus parlant quand on veut représenter des notions concrètes de la vraie vie, ou quand on implémente une machine à état.

Par exemple, vous créez une classe FeuCirculation. Vous avez besoin d’une variable renseignant sa couleur. Vous pouvez utiliser un int à l’arrache, et noter en commentaire quelque part : “0 c’est rouge, 1 c’est vert, 2 c’est orange.”. Mais c’est chiant. Il faut toujours garder en tête les correspondances. On risque d’attribuer des valeurs non documentées. Bref, y’a n’importe quoi dedans et ça pue, (un peu comme une poche à urine).

Avec un enum, tout est plus clair, aussi bien dans le code définissant la classe FeuCirculation, que dans le code qui l’utilise. Et c’est plus robuste.

L’exemple qui est donné très souvent dans les tutoriaux, c’est un enum Animal, contenant les valeurs chien, chat, bœuf musqué, ... Ça fonctionne, mais personnellement cet exemple me gêne un peu. Chaque animal est un objet à part entière. Dans ce cas, il vaudrait mieux créer une classe générique Animal, et la faire hériter. Ce qui permettra ensuite de créer des méthodes telles que manger(), crier(), péter(), ...

If it quacks like a duck, it may have noticed you are fucking it.

Pour décrire plusieurs objets, utilisez des classes. Pour décrire les différents états d’un même objet, utilisez un enum. Pour décrire plusieurs objets simples, utilisez l’un ou l’autre, c’est à vous de choisir.

Comment faire un enum en python ?

Il n’y a, à ma connaissance, pas de structure syntaxique dédiée. Mais c’est pas grave, on va bien trouver quelque chose.

Le plus simple, pour commencer, c’est de garder l’idée de la correspondance avec des entiers. Ça offre plein d’avantages :

  • On sait exactement comment ça marche à l’intérieur.
  • On peut très facilement enregistrer des enums dans un fichier ou une base de donnée, puisque ce ne sont que des nombres.
  • On peut ordonner les valeurs. À utiliser avec prudence, car ça n’a pas toujours de sens. (Dire que l’état “feu rouge” est inférieur à l’état “feu vert”, qu’est-ce que cela signifie exactement ?)

La première idée qui vient à l’esprit, c’est de créer une classe avec les valeurs dedans, et de ne plus jamais les changer par la suite.

# On l'appelle FeuCirculation et non pas FeuRouge. 
# Parce qu'un feu n'est pas forcément rouge.
# (Putain de langue française à la con qui fait n'importe quoi).
class FeuCirculation:
    ROUGE = 0
    ORANGE = 1
    VERT = 2
    ORANGE_CLIGNOTANT = 3
    TOUT_ETEINT = 4

feuActuel = FeuCirculation.ORANGE

C’est bien, mais chiant à maintenir. Si on veut ajouter un autre état (par exemple, FLECHE_DROITE_ORANGE_CLIGNOTANTE), et qu’on se plante dans les valeurs numériques, il y a un risque d’avoir des doublons, et ça fiche tout en l’air.

Voici un petit peu mieux :

class FeuCirculation:
    (ROUGE,
     ORANGE,
     VERT,
     ORANGE_CLIGNOTANT,
     TOUT_ETEINT,
    ) = range(5)

range(5) renvoie un tuple (0, 1, 2, 3, 4). Des entiers différents sont attribués aux valeurs de l’enum. Si on veut en rajouter une et qu’on oublie de remplacer range(5) par range(6), ça va balancer une exception. Tout va bien.

Au cas où vous demanderiez : “qu’est-ce qui m’empêche de redéfinir l’une des valeurs, à un autre endroit du code, et de foutre le bordel ?”, je répondrais “We are all consenting adults here”. (Se référer à la philosophie du python. Si besoin, ce sera l’occasion d’un autre article).

Some consenting adults. (Je peux venir ?)

Le code est beau, mais pour débugger ?

C’est un peu lourdingue. Lorsqu’on fait print feuActuel (ou lorsqu’on tape directement feuActuel dans une console pdb), c’est une valeur numérique pas claire qui va s’afficher, au lieu d’un joli “ORANGE”, “ROUGE”, …

Un petit dictionnaire de correspondance “valeur numérique” -> “nom à afficher” serait de bon aloi. Quelque chose de ce genre, à placer dans la définiton de la classe FeuCirculation :

    dictReverse = {
        ROUGE : "ROUGE",
        ORANGE : "ORANGE",
        VERT : "VERT",
        ORANGE_CLIGNOTANT : "ORANGE_CLIGNOTANT",
        TOUT_ETEINT : "TOUT_ETEINT",
    }

Fort bien. Mais n’est-ce pas un peu casse-couille ? Eh si. Des répétitions à la pelle, et dictReverse doit rester synchro avec les définitions des valeurs. C’est redevenu chiant à maintenir.

Hey, je suis Dict-Reverse, et je suis chiant à maintenir. bi-boppe eu loulaaaa.

Définition dynamique de nouveaux types

Soyons franc, j’ai piqué cette astuce ici :
http://stackoverflow.com/questions/36932/whats-the-best-way-to-implement-an-enum-in-python

Vous connaissez certainement déjà la fonction native type(). Elle renvoie le type du truc passé en paramètre. Youpi.

Mais saviez-vous qu’elle permet également de créer de nouveaux types ? Pour ce faire, il faut l’appeler avec 3 paramètres :

  • Le nom.
  • Une liste indiquant les types de base (dans le cas où on veut que le type soit hérité).
  • Un dictionnaire contenant les attributs. Les clés sont des chaînes de caractère, et correspondront aux noms des attributs.

La création de l’enum FeuCirculation pourrait donc se faire de cette manière :

FeuCirculation = type(
    "FeuCirculation",
    (),
    {
        "ROUGE" : 0, 
        "ORANGE" : 1, 
        "VERT" : 2, 
        "ORANGE_CLIGNOTANT" : 3, 
        "TOUT_ETEINT" : 4
    })

>>> FeuCirculation

>>> FeuCirculation.VERT
2

On peut également ajouter le dictReverse dans le dictionnaire des attributs. (Ça fait un dictionnaire dans un dictionnaire, c’est lol).

FeuCirculation = type(
    "FeuCirculation",
    (),
    {
        "ROUGE" : 0,
        "ORANGE" : 1,
        "VERT" : 2,
        "ORANGE_CLIGNOTANT" : 3,
        "TOUT_ETEINT" : 4,
        "dictReverse" : {
            0 : "ROUGE",
            1 : "ORANGE",
            2 : "VERT",
            3 : "ORANGE_CLIGNOTANT",
            4 : "TOUT_ETEINT"}
    })

>>> FeuCirculation

>>> feuxActuel = FeuCirculation.VERT
>>> feuxActuel
2
>>> FeuCirculation.dictReverse[feuxActuel]
'VERT'

Et maintenant y’a plus qu’à coder une petite fonction qui fait tout ça génériquement.

def enum(enumName, *listValueNames):
    # Une suite d'entiers, on en crée autant
    # qu'il y a de valeurs dans l'enum.
    listValueNumbers = range(len(listValueNames))
    # création du dictionaire des attributs.
    # Remplissage initial avec les correspondances : valeur d'enum -> entier
    dictAttrib = dict( zip(listValueNames, listValueNumbers) )
    # création du dictionnaire inverse. entier -> valeur d'enum
    dictReverse = dict( zip(listValueNumbers, listValueNames) )
    # ajout du dictionnaire inverse dans les attributs
    dictAttrib["dictReverse"] = dictReverse
    # création et renvoyage du type
    mainType = type(enumName, (), dictAttrib)
    return mainType

>>> FeuCirculation = enum(
        "FeuCirculation",
        "ROUGE", "ORANGE", "VERT",
        "ORANGE_CLIGNOTANT", "TOUT_ETEINT")
>>> FeuCirculation.TOUT_ETEINT
4
>>> FeuCirculation.dictReverse[FeuCirculation.TOUT_ETEINT]
'TOUT_ETEINT'

Une petite précision : d’habitude, quand on crée des classes ou des types, c’est pour les instancier. Là on ne le fait pas, on se contente d’utiliser des valeurs statiques contenues dans le type. Vous pourriez faire feuDuCarrefour = FeuCirculation(). Ça va fonctionner, mais ça ne vous servira à rien.

Le code de la route a parfois besoin de refactoring

Mais si on mélange les enums ?

>>> FeuCirculation = enum(
        "FeuCirculation",
        "ROUGE", "ORANGE", "VERT",
        "ORANGE_CLIGNOTANT", "TOUT_ETEINT")
>>> etatMatiere = enum(
        "etatMatiere", 
        "SOLIDE", "LIQUIDE", "GAZEUX")
>>> etatMatiere.dictReverse[FeuCirculation.VERT]
'GAZEUX'

Mince alors. Ça fait n’importe quoi, sans signaler aucune erreur. C’est normal. D’un enum à l’autre, on ne fait que manipuler des entiers, qui restent les mêmes. Les correspondances se font joyeusement, même si ça n’a aucun sens. Dans le même ordre d’idée : FeuCirculation.ROUGE == etatMatiere.SOLIDE renverra True, ce qui ne veut rien dire. Comment régler ce problème ?

Better have traffic ice than traffic jam.

Solution 1 : ne pas régler le problème

“We are all consenting adults here”, on ne va donc pas compliquer le code en rajoutant des sécurités de partout, sous prétexte d’empêcher des erreurs. Le seule moyen valable de se prémunir de faire n’importe quoi quand on code, c’est tout bêtement de rester concentré et de faire gaffe à ce qu’on fait.

Honnêtement, ça ne m’est jamais arrivé de mélanger des enums entre eux. Pourtant, je n’ai pas la prétention de tout faire juste et sans bugs du premier coup. Parmi mes bourdes préférées : copier-coller la ligne du dessus et ne pas faire les bons remplacements (les “x” par des “y”, les “1” par des “2”, etc.), ou encore : déclarer une fonction, lui faire renvoyer un résultat bidon parce que je préfère la coder plus tard, et oublier que je ne l’ai pas codé.

def calculDist(point1, point2):
    distX = point1.x - point1.x
    distY = point2.x - point2.x
    return math.sqrt(distX * distX + distY * distY)
    # ami lecteur, sauras-tu trouver tous les fails
    # présents dans cette fonction ?

def RemoveDoubleLetters(strValue):
    # TODO : coder le truc. Mais là, j'ai la flemme.
    return strValue

BSOD !!

Pour limiter les risques de mélange, voici quelques conseils :

  • Préfixez les variables contenant une valeur d’enum : feu pour FeuCirculation, emat pour etatMatiere, etc. De cette manière, les erreurs de code sautent aux yeux. (making wrong code look wrong, tout ça…)
  • Il est important de ne pas polluer inutilement l’espace de nommage. Dans un fichier donné, n’importez pas les enums dont vous n’avez pas besoin. De cette manière, une erreur sera renvoyée si jamais vous utilisez une valeur d’enum imprévue. Je doute que vous ayez besoin, dans un même fichier de code, de renseigner des états de feux rouge et des états de matière.
  • Si vous faites exprès de mélanger des enums, en pensant que vous n’avez aucun moyen de faire autrement, c’est qu’il y a, dès l’origine, un problème de conception dans votre code.

Vieng fayre toi-même leu mélainge des enums, sur les muuuurs deu la cabaneu du côdeur. Vieng t'assouar.

Solution 2 : des enums fortement typés.

Au lieu que les valeurs internes des enums soient de simples entiers, on crée un type pour chacune d’elle. Comme ça, on est sûr que ça renverra une erreur si on se confusionne. Par contre, on perd en simplicité, et ce n’est plus aussi simple pour la sérialisation.

Soyons fous, et voyons ce que ça donne !

def strongTypedEnum(enumName, *listValueNames):
    # création d'une liste de type. sans attribut, sans héritage.
    # le nom du type est composé du nom de l'enum et du nom de la valeur,
    # séparés par un point.
    listValueTyped = [ type(".".join((enumName, nameValue)), (), {})
                       for nameValue in listValueNames ]
    # Ensuite, c'est tout pareil que la fonction d'avant.
    dictAttrib = dict( zip(listValueNames, listValueTyped) )
    dictReverse = dict( zip(listValueTyped, listValueNames) )
    dictAttrib["dictReverse"] = dictReverse
    mainType = type(enumName, (), dictAttrib)
    return mainType

>>> FeuCirculation = strongTypedEnum("FeuCirculation",
        "ROUGE", "ORANGE", "VERT",
        "ORANGE_CLIGNOTANT", "TOUT_ETEINT")
>>> etatMatiere = strongTypedEnum(
        "etatMatiere", 
        "SOLIDE", "LIQUIDE", "GAZEUX")
>>> etatMatiere.LIQUIDE

>>> etatMatiere.dictReverse[FeuCirculation.ROUGE]
Traceback (most recent call last):
  File "", line 1, in 
    etatMatiere.dictReverse[FeuCirculation.ROUGE]
KeyError: 

Mais est-ce bien nécessaire ?

Y’a une lib pour ça

Comme toujours, avec cette foutue prolifération de code libre, dès que quelque chose de cool peut potentiellement exister, un connard de geek l’a déjà fait, vous privant de l’occasion de le faire vous-même et de retirer la gloire qui en décombe. La lib flufl.enum permet donc de créer et manipuler des enums, avec autant et même plus de fonctionnalités que ce que je viens de décrire ici. (Connards de geeks qui viennent manger le pain des français).

Par contre, j’ai regardé le code, et j’ai pas pigé comment ça fonctionnait à l’intérieur. Ça fera peut-être l’objet d’un autre article, si j’ai le courage de me plonger dedans, et que je trouve ça intéressant et rigolo.

De toutes façons, les libs c’est chiant, ça ajoute des dépendances, il vaut mieux tout coder à la main.

Disgression 1 : quelle classe ce type !

Déclarer un type avec la fonction type(), et déclarer une classe, ça ne fait pas exactement la même chose.

>>> class MaClasse:
	pass

>>> MaClasse

>>> instanceClasse = MaClasse()
>>> instanceClasse
<__main__.MaClasse instance at 0x011C8BC0>

>>> MonType = type("Le_Nom_De_Mon_Type", (), {})
>>> MonType

# Hey ! Le nom est dans une string, et y'a pas d'adresse mémoire !

>>> instanceType = MonType()
>>> instanceType
<__main__.Le_Nom_De_Mon_Type object at 0x011C1B30>
# Hey ! C'est un object, et pas une instance !

Ça a peut-être quelque chose à voir avec une histoire de old-style class et new-style class. J’ai pas cherché plus loin pour l’instant. Ça fera peut-être l’objet d’un autre-autre article, si j’ai le courage de me plonger dedans, et que je trouve ça intéressant et rigolo.

Disgression 2 : Restons dans les règles

J’avais trouvé un autre exemple de machine à état, plus rigolo que des feux de circulation ou de la matière. Je ne m’en suis pas servi durant mes explications, parce que ça aurait distrait le lecteur / la lectrice (charge cérébrale, tout ça…). Mais ce serait vraiment dommage de ne pas vous en faire profiter. Le voici donc :

>>> PhaseCycleUterin = enum(
        "PhaseCycleUterin",
        "PREPUBERE", "MENSTRUELLE", 
        "OVULATION", "PROLIPERATIVE", "SECRETRICE"
        "ENCEINTE", "MENOPAUSE")

>>> etatMatiere.dictReverse[PhaseCycleUterin.MENSTRUELLE]
'LIQUIDE'

Voilà, ce sera tout pour aujourd’hui. La prochaine fois, nous redéfinirons le type “object” en utilisant uniquement les picots du langage Braille.

Une femme qui a ses règles.

]]>
http://sametmax.com/faire-des-enums-en-python/feed/ 59 3741
id(), None et bidouilleries mémoire en python. http://sametmax.com/id-none-et-bidouilleries-memoire-en-python/ http://sametmax.com/id-none-et-bidouilleries-memoire-en-python/#comments Sat, 10 Nov 2012 17:37:54 +0000 http://sametmax.com/?p=2947

Ceci est un post invité de Réchèr posté sous licence creative common 3.0 unported.

Mon maître-ninja python, entre deux riffs sur sa contrebasse électrique, m’avait un jour dit : “il ne faut pas écrire if a == None:, mais if a is None:“. Il m’avait ensuite donné une justification pertinente, que je n’ai pas retenue, car j’étais en train de penser à des nichons. Puis il avait conclu par “on n’est pas égal au vide. On EST le vide.”

Rien que pour vous, ainsi que pour m’auto-déculpabiliser de penser souvent à des nichons, j’ai parcouru l’internet entier à dos de souris et j’ai retrouvé la justification. Mais avant de vous la livrer, quelques explications préliminaires.

On n’a pas de pétrole, mais on a des id()

Et quand on n'a pas d'id, on a des fix !

La fonction id(), présente dans __builtins__, renvoie un entier, représentant l’identifiant interne de n’importe quel objet, quel que soit son type. Concrètement, il s’agit de l’adresse mémoire dans laquelle il est stocké. Jouons un peu avec.

»» a = 1
»» id(a)
19846928
»» b = "plop"
»» id(b)
33984800
»» id(2)
19846916

Si vous faites cela chez vous, vous n’obtiendrez certainement pas les mêmes nombres. Ce qui est important à repérer, c’est que dans ce premier exemple, tous les id sont différents. Au passage, vous remarquerez que même les constantes ont un id. Je ne sais pas exactement comment cela fonctionne en interne, mais je suppose que lorsqu’on écrit le chiffre 2, on oblige le python à stocker cette valeur dans une sorte de monde magique contenant tout ce qui a été utilisé depuis le début de l’exécution, même si certaines de ces valeurs ne sont plus référencées nul part.

Il est parfois intéressant de vérifier que deux id sont égaux ou différents. Mais vous ne pouvez pas faire grand chose de plus. Les caractères de la chaîne “plop” sont, à priori, stockés les uns à la suite des autres, dans une seule zone mémoire (tous les langages de programmation gèrent les strings de cette manière), mais vous ne pouvez pas mettre ce fait en évidence.

»» id(b[0])
19483368
»» id(b[1])
19989736
»» id(b[2])
19989760
»» id(b[0:2])
31983736
»» id(b[1:3])
31983424

Les adresses ne se suivent pas, et ne sont même pas rangées dans l’ordre croissant. Ce n’est pas vraiment exploitable. En revanche, il y a quelque chose de rigolo à constater :

»» c = "pouet"
»» d = "pouet"
»» id(c)
33984768
»» id(d)
33984768
»» id("pouet")
33984768

On a deux variables différentes, contenant la même chose, et elles pointent sur la même adresse mémoire. Mais alors, si je modifie c, ça va aussi modifier d ! Ohlala, Comment le python va faire ? Rassurez-vous, il s’en sort.

»» c += "a"
»» c
'poueta'
»» d
'pouet'
»» id(c)
33855904
»» id(d)
33984768

Le type string est immutable (ndm aussi: “immuable”). Cela signifie que vous ne pouvez rien changer dedans. Tout ce que vous pouvez faire, c’est réaffecter des variables (à une autre string, à n’importe quoi, …). Dans cet exemple, la réaffectation de c l’a fait pointer sur une autre zone de la mémoire. Mais sinon, la variable d n’a pas changé, ni son pointage, ni le contenu de ce qui est pointé. Ouf !!

Je te fais "pouet-pouet", tu me fais "pouet-pouet" ...

Au passage, je rappelle que toutes les fonctions de traitement de chaîne de caractères (replace(), upper(), strip(), …) ne font jamais la modification “sur place”. Elles renvoient la valeur sous forme d’une nouvelle string. Si vous voulez modifier sur place, vous êtes obligés de faire une réaffectation explicite. Quelque chose comme : c = c.upper()

Bidouilleries optimisatoires internes

Je sens que vous redemandez encore du jeu de mots pourri. So, here comze da None !

Le fait qu’un objet soit immutable n’oblige pas le python à créer une seule zone mémoire par valeur. Dans l’exemple précédent, lorsque j’ai affecté les variables c et d à “pouet”, leurs id auraient pu être différentes dès le départ, et les zones mémoires pointées auraient toutes les deux contenues “pouet”. Il se trouve que le python les a mises en commun, par souci d’optimisation. Cependant, je ne suis pas sûr que cette technique soit appliquée par tous les interpréteurs, toutes les versions, et dans tous les contextes. Mais “chez moi, ça marche”.

Cette optimisation est également effectuée pour les valeurs booléennes et les valeurs numériques entières. Mais pas pour les floats, alors qu’à ma connaissance, ils sont eux aussi immutables.

»» id(True)
505281316
»» id(True)
505281316
»» id(False)
505280988
»» id(False)
505280988
»» id(10)
19846820
»» id(10)
19846820
»» id(10.0)
19879104
»» id(10.0)
31338664
# Refaites des id(10.0), et vous aurez encore d'autres valeurs différentes.
# Mais peut-être pas à chaque fois. On ne peut pas le prévoir.

En revanche, l’optimisation de la valeur None est garantie, quel que soit votre python et son contexte. Il n’y a toujours qu’une et une seule instance de None dans une exécution de python. Je n’ai pas trouvé d’annonce officielle concernant cette garantie, mais ça se dit un peu partout sur les forums. (Et si c’est sur internet, c’est forcément vrai).

Jouons un peu avec la singletonitude du None.

»» id(None)
505255972
»» z = None
»» id(z)
505255972
»» zzzz = [None, ] * 30
»» zzzz
[None, None, None, None, None, None, None, None, None, None, None, None, None,
None, None, None, None, None, None, None, None, None, None, None, None, None,
None, None, None, None]
»» [ id(elem) for elem in zzzz ]
[505255972, 505255972, 505255972, 505255972, 505255972, 505255972, 505255972,
505255972, 505255972, 505255972, 505255972, 505255972, 505255972, 505255972,
505255972, 505255972, 505255972, 505255972, 505255972, 505255972, 505255972,
505255972, 505255972, 505255972, 505255972, 505255972, 505255972, 505255972,
505255972, 505255972]

Disgression : les mot-clés True et False peuvent être réaffectés. Mais pas le mot-clé None. Mais je m’égare. Revenons à nos agneaux, comme dirait Hannibal Lecter.

noir is noir. (Il n’y a plus d’ayspouuaaaarr).

"Mmmmppff... psshhhh..." (#000000 Vador)

Laissez-moi maintenant vous introduire (schlorrp) l’opérateur is. Il est présent nativement dans le python, et permet de comparer les id de deux objets. A is B renvoie un booléen, le même que celui que renverrait id(A) == id(B).

A quoi cela pourrait-il donc servir ? Eh bien … De même que la fonction id ne sert pas à grand chose, is est, lui aussi, d’une utilité discutable. Mais attendez, ne partez pas tout de suite.

L’opérateur is est vraiment tout simple. Il ne peut pas être surchargé, et fait toujours la même chose quel que soit les opérandes : une comparaison d’id.

L’opérateur == a l’air tout bête, vu comme ça, mais il peut être surchargé, et il effectue une suite d’actions pas forcément triviales. Il appelle la fonction __eq__ si elle existe, sinon il essaie avec la fonction __cmp__, et peut-être encore d’autres choses que je ne détaillerai pas ici, parce que je ne me suis pas renseigné en détail sur le sujet. (Faut que je conserve une partie de mon temps pour le pensage à des nichons, vous comprenez bien).

En règle générale, dès que c’est possible, il vaut mieux utiliser un truc simple plutôt qu’un truc compliqué. Malheureusement, comme on ne maîtrise pas vraiment la façon dont les id sont gérés et optimisés, l’utilisation du is serait trop risquée. Sauf dans un cas bien identifié. Devinez lequel ?

Le None, qui n’a toujours qu’une et une seule id ! Joie ! Noël !

Au fait, pendant qu’on y est, ne pourrait-on pas utiliser is avec les valeurs True et False ? A priori, ces deux valeurs sont gérées de la même manière que le None ?

Certes, mais pour les booléens, on a encore plus simple. Au lieu de tester if A is True: ou if A == True:, on peut directement tester if A:. Pour False, on teste if not A:. Voili voilà.

Le béni oui-oui

Un béni oui-oui !

Pour finir, une petite justification supplémentaire, que je n’ai jamais rencontré dans la vraie vie, mais on va faire comme si.

Alors voilà, vous êtes quelqu’un de bizarre, et vous avez besoin d’une classe qui est égale à tout. Donc vous surchargez la fonction __eq__.

»» class BeniOuiOui:
    def __eq__(self, other):
        # Je suis une classe magique, qui est égale à tout ce qui existe !
        return True
»» beniOuiOui = BeniOuiOui()

Un peu plus loin dans le code, vous avez une variable, récupérée d’on ne sait trop où, et vous voulez savoir si c’est None, ou si c’est une instance de béni-oui-oui. Pour faire cela, vous êtes obligés d’utiliser is, car == vous répondrait systématiquement True.

»» beniOuiOui == 2
True
»» beniOuiOui == "n'importe quoi"
True
»» beniOuiOui == None
True
»» beniOuiOui is None
False

this (is not) une pipe

Ce serait même plutôt le contraire.

Comment fait-on pour vérifier que quelque chose n’est pas None ? La première réponse qui vient à l’esprit, c’est not A is None. Mais on peut aussi utiliser A is not None. C’est chouette, ça ressemble à du langage naturel.

Oh, mais, attendez … Est-ce que cette écriture n’est pas un peu dangereuse ?

»» not None
True

not None renvoie True. Pourquoi pas. C’est ce qui semble le plus logique.

»» 1 is True
False

1 is True est faux. Ca semble correct aussi. La valeur numérique 1 et la valeur booléenne True sont égales, mais ce ne SONT pas les mêmes objets.

Mais alors, si j’écris 1 is not None, le python va transformer le not None en True, ça va faire 1 is True, et ça va renvoyer faux. Ce n’est pas ce que je veux ! La valeur numérique 1, ce n’est pas None. Moi je veux que 1 is not None me renvoie vrai.

Arrggh ! Pleurons mes amis ! Et regardons avec horreur le python se désintégrer tout seul dans une bouffée de logique !

»» 1 is not None
True

Ah tiens non. Hmmm… Attendez voir…

»» 1 is (not None)
False

Qu’est-ce donc que cela ? Figurez-vous que is not est un opérateur. Il compare les id, et renvoie True s’ils sont différents. Je vous laisse confirmer cela en consultant la doc du python, ou en faisant un petit help("is") dans la console.

Voilà, j’espère que ça vous a plu. La prochaine fois, nous essaierons de déceler dans le langage Brainfuck des éléments de la thèse existentialiste selon Jean-Paul Sartre.

]]>
http://sametmax.com/id-none-et-bidouilleries-memoire-en-python/feed/ 21 2947