# articles

feed_id: http://sametmax.com/?p=12217
title: Le blog a été migré (enfin presque)
uri: Le-blog-a-été-migré-(enfin-presque)
url: http://sametmax.com/le-blog-a-ete-migre-enfin-presque/
content:
<p>Max a pris l&#8217;hébergement et a setup Varnish (sans lequel le WP s&#8217;écroule sous la masse de vos pattes velues), puis j&#8217;ai installé WP 4, et migré la DB et les images.</p>
<p>En gros, vous pouvez de nouveau lire vos articles techniques préférés. Et les autres aussi.</p>
<p>Par contre, feu notre ancien thème (snif, il était si&#8230; si&#8230; attachant&#8230;), et donc tous les easter eggs qui vont avec.</p>
<p>Vous noterez donc un blog moins fun, avec des bugs graphiques et surtout, sans plugins, donc ouvert aux 4 vents aux spams mais sans formulaire de contact. Mouarf.</p>
<p>Je vais corriger ça petit à petit, mais je ne me presse pas, l&#8217;avantage d&#8217;écrire un blog bénévole est qu&#8217;on ne doit rien à personne, donc on peut se gratter les couilles.</p>
<p>0bin, multiboards et allthatcount vont suivre. Je vais probablement les migrer avant de m&#8217;attaquer à la corrections des petits problèmes du blog d&#8217;ailleurs.</p>
<p>La base de données complète a été migrée. Félicitation à l&#8217;équipe de WP pour avoir mis en œuvre un outil de conversion des tables d&#8217;une version à l&#8217;autre parfaitement transparent. C&#8217;est pas facile à faire, et ça marche super bien. Mettez l&#8217;article en favoris, je ne dirais pas souvent du bien de cet outil.</p>
<p>Ça signifie que vos commentaires sont là, les pages statiques aussi, et bien entendu, pour les contributeurs, leurs comptes utilisateurs également. Il y a eu un bug de login ce matin, mais c&#8217;est réparé.</p>
<p>Si vous voyez des trucs qui pètent, merci de les lister en comment ici que je puisse avoir une check list à jour et sans doublons. Avec les URLS c&#8217;est mieux.</p>
<p>Parmi les problèmes que je vois venir : les iframes qui marchent pas, la barre de menu de droite qui déconne, et autres joyeusetés, des médias de mauvaise taille.</p>
<p>Et bonne lecture :)</p>


feed_id: http://sametmax.com/?p=11783
title: Un bot qui tweete 4992 Super-Héros à raison de un toutes les 3,14 heures peut-il sauver Internet ?
uri: Un-bot-qui-tweete-4992-Super-Héros-à-raison-de-un-toutes-les-3-14-he
url:
http://sametmax.com/un-bot-qui-tweete-4992-super-heros-a-raison-de-un-toutes-les-314-heures-peut-il-sauver-internet/

content:
<p style="text-align: center;"><em><small>Ceci est un post invité de <a href="http://sametmax.com/author/01ivier/">01ivier</a> posté sous licence <a href="http://creativecommons.org/licenses/by/3.0/">creative common 3.0 unported</a>.</small></em></p>
<p>Depuis l&#8217;Antiquité, en moyenne, environ une seule personne s&#8217;est posée cette question, dont moi.</p>
<p>Je me propose donc de partager avec vous mon expérience sur le sujet en vous expliquant ce que j&#8217;ai mis en œuvre pour tenter d&#8217;obtenir une réponse.</p>
<h2>Bonsjours, je voudrais tweeter en Python, s&#8217;il vous plaît.</h2>
<p>Il existe plusieurs bibliothèques en Python qui papotent avec l&#8217;API de Twitter. <a href="https://dev.twitter.com/docs/twitter-libraries">Neuf sont actuellement référencées par Twitter</a>.</p>
<p>Parce qu&#8217;il y avait écrit &#8220;Actively maintained&#8221;, j&#8217;ai tenté <a href="https://github.com/ryanmcgrath/twython">twython</a> .</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #c20cb9; font-weight: bold;">sudo</span> pip <span style="color: #c20cb9; font-weight: bold;">install</span> twython</pre></td></tr></table></div>

<p>Il se trouve qu&#8217;elle fait très bien ce que j&#8217;attendais d&#8217;elle, donc je ne suis pas allé chercher plus loin.</p>
<p>Par ailleurs, le code pour envoyer un tweet est flippant de simplicité :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">from</span> twython <span style="color: #ff7700;font-weight:bold;">import</span> Twython
&nbsp;
APP_KEY <span style="color: #66cc66;">=</span> <span style="color: #483d8b;">&quot;votre petite clef-clef à vous&quot;</span>
APP_SECRET <span style="color: #66cc66;">=</span> <span style="color: #483d8b;">&quot;une autre petite clef-clef&quot;</span>
OAUTH_TOKEN <span style="color: #66cc66;">=</span> <span style="color: #483d8b;">&quot;encore une petite clef-clef&quot;</span>
OAUTH_TOKEN_SECRET <span style="color: #66cc66;">=</span> <span style="color: #483d8b;">&quot;enfin, une dernière petite clef-clef&quot;</span>
&nbsp;
twitter <span style="color: #66cc66;">=</span> Twython<span style="color: black;">&#40;</span>APP_KEY<span style="color: #66cc66;">,</span> APP_SECRET<span style="color: #66cc66;">,</span> OAUTH_TOKEN<span style="color: #66cc66;">,</span> OAUTH_TOKEN_SECRET<span style="color: black;">&#41;</span>
&nbsp;
texte <span style="color: #66cc66;">=</span> <span style="color: #483d8b;">'Oh mon Dieu ! Mais cette librairie crache des flammes ! #Twython'</span>
&nbsp;
twitter.<span style="color: black;">update_status</span><span style="color: black;">&#40;</span>status<span style="color: #66cc66;">=</span>texte<span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>Et paf :</p>
<blockquote class="twitter-tweet" lang="fr"><p>Oh mon Dieu ! Mais cette librairie crache des flammes ! <a href="https://twitter.com/hashtag/Twython?src=hash">#Twython</a></p>
<p>— AllStarsNetSupaHeros (@4992SuperHeros) <a href="https://twitter.com/1881SuperHeros/statuses/499002145862320128">12 Août 2014</a></p></blockquote>
<p>&nbsp;</p>
<p>Pour obtenir ses <em>petites clefs-clefs</em>, il est nécessaire de se créer un compte sur <a href="http://dev.twitter.com/">la plate-forme de Twitter réservée aux développeurs</a>.</p>
<p>Je vous la fait courte :</p>
<p>&gt; <em>My applications</em> dans le menu de votre icône en haut à droite &gt; <em>Create New Apps</em><br />
&gt; Remplir le formulaire &gt; accepter les conditions d&#8217;utilisation <a href="http://www.legorafi.fr/2014/07/15/ivre-elle-lit-lintegralite-des-conditions-dutilisation-ditunes/">après les avoir lues</a><br />
&gt; <em>Permissions</em> &gt; <em>Read and Write</em><br />
&gt; <em>API Keys</em> &gt; <em>Generate my acces token</em></p>
<p>La partie la plus compliquée pour moi fut de passer les permissions en &#8220;<strong>Read and Write</strong>&#8220;.</p>
<p>En effet, il faut <strong>associer un numéro de téléphone au compte twitter</strong> utilisé et la manipulation doit être faite à partir du téléphone en question.<br />
Or, je n&#8217;ai pas de téléphone portable.</p>
<p>Heureusement, la femme de ma <strong>Vie</strong> a eu la bonne idée de faire l&#8217;<strong>Amour</strong> il y a 17 ans et sa fille, la fille de ma <strong>Vie</strong>, possède ce genre d&#8217;appareil.<br />
Sauvé.</p>
<p>Si vous n&#8217;avez pas de fille de votre <strong>Vie</strong>, ni même de femme de votre <strong>Vie</strong>, faites en sorte d&#8217;avoir un téléphone portable.</p>
<p>(J&#8217;ai mis <strong>Amour</strong> et <strong>Vie</strong> en gras pour gagner des points de Karma. Je ne sais pas si ça marche, mais je me dis que ce serait tout de même bien malheureux que ça ait un effet négatif.)</p>
<h2>Bonsjours, je voudrais ajouter une image au tweet que je tweete en Python, s&#8217;il vous plaît.</h2>
<p>En partant du principe que vous avez une <em>image.png</em> à côté de votre script :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">from</span> twython <span style="color: #ff7700;font-weight:bold;">import</span> Twython
&nbsp;
APP_KEY <span style="color: #66cc66;">=</span> <span style="color: #483d8b;">&quot;votre petite clef-clef à vous&quot;</span>
APP_SECRET <span style="color: #66cc66;">=</span> <span style="color: #483d8b;">&quot;une autre petite clef-clef&quot;</span>
OAUTH_TOKEN <span style="color: #66cc66;">=</span> <span style="color: #483d8b;">&quot;encore une petite clef-clef&quot;</span>
OAUTH_TOKEN_SECRET <span style="color: #66cc66;">=</span> <span style="color: #483d8b;">&quot;enfin, une dernière petite clef-clef&quot;</span>
&nbsp;
twitter <span style="color: #66cc66;">=</span> Twython<span style="color: black;">&#40;</span>APP_KEY<span style="color: #66cc66;">,</span> APP_SECRET<span style="color: #66cc66;">,</span> OAUTH_TOKEN<span style="color: #66cc66;">,</span> OAUTH_TOKEN_SECRET<span style="color: black;">&#41;</span>
&nbsp;
texte <span style="color: #66cc66;">=</span> <span style="color: #483d8b;">'Mais quelle folie ! #Twython tweete aussi des images ! '</span>
image <span style="color: #66cc66;">=</span> <span style="color: #008000;">open</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;image.png&quot;</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'rb'</span><span style="color: black;">&#41;</span>
&nbsp;
twitter.<span style="color: black;">update_status_with_media</span><span style="color: black;">&#40;</span>status<span style="color: #66cc66;">=</span>texte<span style="color: #66cc66;">,</span> media<span style="color: #66cc66;">=</span>image<span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>Et hop :</p>
<blockquote class="twitter-tweet" lang="fr"><p>Mais quelle folie ! <a href="https://twitter.com/hashtag/Twython?src=hash">#Twython</a> tweete aussi des images ! <a href="http://t.co/1sK9RH2qdP">pic.twitter.com/1sK9RH2qdP</a></p>
<p>— AllStarsNetSupaHeros (@4992SuperHeros) <a href="https://twitter.com/1881SuperHeros/statuses/499003722715103232">12 Août 2014</a></p></blockquote>
<p>&nbsp;</p>
<p>J&#8217;ai du mal à imaginer qu&#8217;on puisse faire plus simple.</p>
<h2>Maintenant, j&#8217;aimerais tweeter toutes les 3,14 heures. C&#8217;est possible ?</h2>
<p>Pour tweeter toutes les 3 heures, une petite <a href="http://fr.wikipedia.org/wiki/Crontab">crontab</a> réglée de la sorte aurait fait l&#8217;affaire :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #000000;">0</span> <span style="color: #000000; font-weight: bold;">*/</span><span style="color: #000000;">3</span> <span style="color: #000000; font-weight: bold;">*</span> <span style="color: #000000; font-weight: bold;">*</span> <span style="color: #000000; font-weight: bold;">*</span> python chemin<span style="color: #000000; font-weight: bold;">/</span>vers<span style="color: #000000; font-weight: bold;">/</span>mon<span style="color: #000000; font-weight: bold;">/</span>script.py</pre></td></tr></table></div>

<p>Mais pour 3,14 heures, il faut faire dans le délicat.<br />
Je fais donc patienter le script 11 304 secondes entre chaque envoi :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">from</span> <span style="color: #dc143c;">time</span> <span style="color: #ff7700;font-weight:bold;">import</span> sleep
&nbsp;
<span style="color: #ff7700;font-weight:bold;">while</span> <span style="color: #008000;">True</span>:
&nbsp;
	envoie_moi_donc_un_tweet_avec_une_image_de_Super_Heros_du_Net<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
	sleep<span style="color: black;">&#40;</span><span style="color: #ff4500;">11304</span><span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>Tout à fait cochon.<br />
Tout à fait parfait.</p>
<h2>Et pour les 4992 Super-Héros.<br />
Comment fait-on ?</h2>
<p>Alors là, vous n&#8217;allez pas être déçus.</p>
<p>Afin de d&#8217;obtenir 4992 Super-Héros, je me suis dit qu&#8217;il me suffisait de trouver 24 têtes de Super-Héros, 13 torses de Super-Héros et 16 jambes de Super-Héros puis de réaliser toutes les combinaisons possibles de ces trois éléments.</p>
<p>24 * 13 * 16 = <strong>4992</strong></p>
<p>Hasard de folie, il se trouve qu&#8217;afin de récolter des fonds pour mener à bien leurs actions, <a href="https://www.laquadrature.net/fr">La Quadrature Du Net</a> propose une petite appli de personnalisation de Super-Héros pour celles et ceux qui <a href="http://soutien.laquadrature.net/">font un don</a>.</p>
<p><a href="http://sametmax.com/ou-il-est-presente-une-methode-en-python-pour-afficher-de-la-video-3-bit-dans-son-terminal/interface_quadrature-3/" rel="attachment wp-att-11841"><img class="aligncenter size-full wp-image-11841" title="interface_quadrature" src="media/e712ea44.interface_quadrature1.png" data-original-source="http://sametmax.com/wp-content/uploads/2014/06/interface_quadrature1.png" alt="" width="600" height="368" /></a></p>
<p>Et bien, aussi incroyable que cela puisse paraître, elle propose de choisir parmi 24 têtes de Super-Héros du Net, 13 torses de Super-Héros du Net, 16 jambes de Super-Héros du Net.</p>
<p>L&#8217;émotion est un peu retombée, mais, sur le moment, j&#8217;ai eu la chaire de poule face à une telle coïncidence, surtout quand on sait que La Quadrature <strong>défend les droits et les libertés des citoyens sur Internet</strong> depuis 2008 et que c&#8217;est pile-poil dans la thématique de la question qui fait l&#8217;objet de cet article.</p>
<p>Me voilà donc parti pour trouver un moyen de récupérer tous ces morceaux de Super-Héros du Net et de reconstituer les 4992 Super-Héros entiers possibles.</p>
<p>Pour retrouver l&#8217;adresse de chaque morceau, un simple coup d’œil au code-source de la page a suffi.</p>
<p><a href="http://sametmax.com/un-bot-qui-tweete-4992-super-heros-a-raison-de-un-toutes-les-314-heures-peut-il-sauver-internet/source_1881/" rel="attachment wp-att-11928"><img class="aligncenter size-full wp-image-11928" title="source_4992" src="media/b32dc5b2.source_1881.png" data-original-source="http://sametmax.com/wp-content/uploads/2014/08/source_1881.png" alt="" width="600" height="541" /></a></p>
<p>Ensuite, en terme de n&#8217;importe quoi je vous propose un morceau de choix.</p>
<p>Car pour faire ma petite popote, j&#8217;ai utilisé <a href="http://processing.org/">Processing</a>.</p>
<p>_ Processing ?!?!<br />
_ Oui. Processing.<br />
_ Mais&#8230; ça utilise une syntaxe Java, ça. Non ?<br />
_ Oui. Mais pour Sam&amp;Max j&#8217;ai utilisé <a href="https://github.com/jdf/processing.py">le mode Python qui vient tout juste de sortir</a>.<br />
_ Utiliser un &#8220;framework Java&#8221; en Python. Excuse-moi, mais c&#8217;est un peu n&#8217;importe quoi.<br />
_ Tout à fait.</p>
<p>Pour celles et ceux qui ne le connaissent pas, Processing est un logiciel/langage conçu pour que les artistes, les graphistes, les designers et les grosses bubuses comme moi puissent facilement et rapidement produire du code créatif (image, son, vidéo).</p>
<p>Je ne vais pas vous faire un cours. Il y a un <a href="http://fr.flossmanuals.net/processing/">FLOSS Manual en français</a> pour ça.</p>
<p>Utilisant Processing depuis plusieurs années, je vous avoue que le mode Python m&#8217;a clairement donné l&#8217;impression de faire du skate avec des rollers, mais comme outils pédagogique, ça doit être pas mal.<br />
Et puis ça marche !</p>
<p>Voici le code que j&#8217;ai pondu pour l&#8217;occasion :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #808080; font-style: italic;"># La fonction setup() est propre à Processing.</span>
<span style="color: #808080; font-style: italic;"># Elle s’exécute en premier et une seule fois.</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> setup<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
&nbsp;
    <span style="color: #808080; font-style: italic;"># On crée une image transparente de 1 pixel de côté qui sera utilisée</span>
    <span style="color: #808080; font-style: italic;"># pour représenter l’absence de choix de tête, de torse et de jambes</span>
    img_vide <span style="color: #66cc66;">=</span> createImage<span style="color: black;">&#40;</span><span style="color: #ff4500;">1</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">1</span><span style="color: #66cc66;">,</span> ARGB<span style="color: black;">&#41;</span>
    img_vide.<span style="color: black;">pixels</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#93;</span> <span style="color: #66cc66;">=</span> color<span style="color: black;">&#40;</span><span style="color: #ff4500;">0</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">0</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># On crée des listes qui contiendront les images des têtes, torses et jambes</span>
    <span style="color: #808080; font-style: italic;"># et on place l'image vide crée juste avant comme premier élément.</span>
    <span style="color: #ff7700;font-weight:bold;">global</span> liste_torses<span style="color: #66cc66;">,</span> liste_tetes<span style="color: #66cc66;">,</span> liste_jambes
    liste_tetes <span style="color: #66cc66;">=</span> <span style="color: black;">&#91;</span>img_vide<span style="color: black;">&#93;</span>
    liste_torses <span style="color: #66cc66;">=</span> <span style="color: black;">&#91;</span>img_vide<span style="color: black;">&#93;</span>
    liste_jambes <span style="color: #66cc66;">=</span> <span style="color: black;">&#91;</span>img_vide<span style="color: black;">&#93;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># On lance le téléchargement de toutes les images nécessaires.</span>
    telechargement_images<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># On fabrique les 4992 Super-Héros avec les images téléchargées.</span>
    usine_super_heros<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> telechargement_images<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
&nbsp;
    <span style="color: #808080; font-style: italic;"># Sachant que chaque image est atteignable par une URL du type</span>
    <span style="color: #808080; font-style: italic;"># http://soutien.laquadrature.net/images/bonus/head_01.png</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># On définit l'URL du dossier où sont situées les images.</span>
    url <span style="color: #66cc66;">=</span> <span style="color: #483d8b;">&quot;http://soutien.laquadrature.net/images/bonus/&quot;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># On télécharge l'image du Super-Héros tout nu qui est placé au fond</span>
    <span style="color: #808080; font-style: italic;"># de chaque image et qui sert de base à tous les autres.</span>
    <span style="color: #ff7700;font-weight:bold;">global</span> base
    base <span style="color: #66cc66;">=</span> loadImage<span style="color: black;">&#40;</span>url + <span style="color: #483d8b;">&quot;base.png&quot;</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># On télécharge les 24 têtes, les 13 torses et les 16 jambes.</span>
    choix_image<span style="color: black;">&#40;</span>url<span style="color: #66cc66;">,</span> <span style="color: #483d8b;">&quot;head_&quot;</span><span style="color: #66cc66;">,</span> liste_tetes<span style="color: #66cc66;">,</span> <span style="color: #ff4500;">24</span><span style="color: black;">&#41;</span>
    choix_image<span style="color: black;">&#40;</span>url<span style="color: #66cc66;">,</span> <span style="color: #483d8b;">&quot;torso_&quot;</span><span style="color: #66cc66;">,</span> liste_torses<span style="color: #66cc66;">,</span> <span style="color: #ff4500;">13</span><span style="color: black;">&#41;</span>
    choix_image<span style="color: black;">&#40;</span>url<span style="color: #66cc66;">,</span> <span style="color: #483d8b;">&quot;legs_&quot;</span><span style="color: #66cc66;">,</span> liste_jambes<span style="color: #66cc66;">,</span> <span style="color: #ff4500;">16</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> choix_image<span style="color: black;">&#40;</span>url<span style="color: #66cc66;">,</span> nom<span style="color: #66cc66;">,</span> liste<span style="color: #66cc66;">,</span> nb_image<span style="color: black;">&#41;</span>:
&nbsp;
    <span style="color: #808080; font-style: italic;"># Pour chaque nombre entre 1 et nb_image (0 correspondant à img_vide),</span>
    <span style="color: #ff7700;font-weight:bold;">for</span> i <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">range</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">1</span><span style="color: #66cc66;">,</span> nb_image<span style="color: black;">&#41;</span>:
&nbsp;
        <span style="color: #808080; font-style: italic;"># on définit un numéro toujours composé de 2 chiffres. Ex: 05 pour 5,</span>
        numero <span style="color: #66cc66;">=</span> <span style="color: #008000;">str</span><span style="color: black;">&#40;</span>i<span style="color: black;">&#41;</span>.<span style="color: black;">zfill</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">2</span><span style="color: black;">&#41;</span>
        <span style="color: #808080; font-style: italic;"># on récupère l'image en recomposant l'URL,</span>
        image_recuperee <span style="color: #66cc66;">=</span> loadImage<span style="color: black;">&#40;</span>url + nom + numero + <span style="color: #483d8b;">&quot;.png&quot;</span><span style="color: black;">&#41;</span>
        <span style="color: #808080; font-style: italic;"># et on ajoute cette image dans la liste correspondante.</span>
        liste.<span style="color: black;">append</span><span style="color: black;">&#40;</span>image_recuperee<span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> usine_super_heros<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
&nbsp;
    <span style="color: #808080; font-style: italic;"># Sachant que toutes images récupérées ont la même taille (214x383)</span>
    <span style="color: #808080; font-style: italic;"># et qu'elles sont des .png transparents dont le contenu trouve sa place</span>
    <span style="color: #808080; font-style: italic;"># quand les images sont parfaitement superposées .</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># On définit une variable qui va compter les 4992 Super-Héros.</span>
    compteur <span style="color: #66cc66;">=</span> <span style="color: #ff4500;">0</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># Pour toutes les images de têtes,</span>
    <span style="color: #ff7700;font-weight:bold;">for</span> tete <span style="color: #ff7700;font-weight:bold;">in</span> liste_tetes:
&nbsp;
        <span style="color: #808080; font-style: italic;"># pour toutes les images de torses,</span>
        <span style="color: #ff7700;font-weight:bold;">for</span> torse <span style="color: #ff7700;font-weight:bold;">in</span> liste_torses:
&nbsp;
            <span style="color: #808080; font-style: italic;"># et pour toutes les images de jambes,</span>
            <span style="color: #ff7700;font-weight:bold;">for</span> jambe <span style="color: #ff7700;font-weight:bold;">in</span> liste_jambes:
&nbsp;
                <span style="color: #808080; font-style: italic;"># on crée un élément graphique de 214x383,</span>
                super_hero <span style="color: #66cc66;">=</span> createGraphics<span style="color: black;">&#40;</span><span style="color: #ff4500;">214</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">383</span><span style="color: black;">&#41;</span>
                <span style="color: #808080; font-style: italic;"># on démarre le dessin de l'élément graphique,</span>
                super_hero.<span style="color: black;">beginDraw</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
                <span style="color: #808080; font-style: italic;"># on place un fond blanc,</span>
                super_hero.<span style="color: black;">background</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">255</span><span style="color: black;">&#41;</span>
                <span style="color: #808080; font-style: italic;"># on place le Super-Héros tout nu aux coordonnées 0, 0</span>
                super_hero.<span style="color: black;">image</span><span style="color: black;">&#40;</span>base<span style="color: #66cc66;">,</span> <span style="color: #ff4500;">0</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">0</span><span style="color: black;">&#41;</span>
                <span style="color: #808080; font-style: italic;"># on place l'image des jambes en 0, 0</span>
                super_hero.<span style="color: black;">image</span><span style="color: black;">&#40;</span>jambe<span style="color: #66cc66;">,</span> <span style="color: #ff4500;">0</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">0</span><span style="color: black;">&#41;</span>
                <span style="color: #808080; font-style: italic;"># on place l'image du torse en 0, 0</span>
                super_hero.<span style="color: black;">image</span><span style="color: black;">&#40;</span>torse<span style="color: #66cc66;">,</span> <span style="color: #ff4500;">0</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">0</span><span style="color: black;">&#41;</span>
                <span style="color: #808080; font-style: italic;"># on place l'image de la tête en 0, 0</span>
                super_hero.<span style="color: black;">image</span><span style="color: black;">&#40;</span>tete<span style="color: #66cc66;">,</span> <span style="color: #ff4500;">0</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">0</span><span style="color: black;">&#41;</span>
                <span style="color: #808080; font-style: italic;"># on clos le dessin de l'élément graphique,</span>
                super_hero.<span style="color: black;">endDraw</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
                <span style="color: #808080; font-style: italic;"># on sauvegarde notre Super-Héros du Net dans le dossier data,</span>
                super_hero.<span style="color: black;">save</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;data/SuperHeros-{0}.png&quot;</span>.<span style="color: black;">format</span><span style="color: black;">&#40;</span>compteur<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
                <span style="color: #808080; font-style: italic;"># et on incrémente le compteur de 1 avant de passer</span>
                <span style="color: #808080; font-style: italic;"># au Super-Héros suivant</span>
                compteur +<span style="color: #66cc66;">=</span> <span style="color: #ff4500;">1</span></pre></td></tr></table></div>

<p>Et hop !</p>
<p><a href="http://sametmax.com/un-bot-qui-tweete-4992-super-heros-a-raison-de-un-toutes-les-314-heures-peut-il-sauver-internet/allstar/" rel="attachment wp-att-12001"><img class="aligncenter size-full wp-image-12001" title="AllStar" src="media/63e1bf3f.AllStar.png" data-original-source="http://sametmax.com/wp-content/uploads/2014/08/AllStar.png" alt="" width="600" height="500" /></a></p>
<h2>Et sinon, c&#8217;est encore loin Grand Schtroumpf ?</h2>
<p>On arrive au bout.</p>
<p>Pour ne pas tweeter les Super-Héros du Net dans l&#8217;ordre et pour ne pas non plus poster deux fois le même en cas de croutage du serveur, je me suis créé un petit <em>ordre.txt</em> comme cela :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">from</span> <span style="color: #dc143c;">random</span> <span style="color: #ff7700;font-weight:bold;">import</span> shuffle
&nbsp;
tous_les_numeros <span style="color: #66cc66;">=</span> <span style="color: #008000;">range</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">4992</span><span style="color: black;">&#41;</span>
shuffle<span style="color: black;">&#40;</span>tous_les_numeros<span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">with</span> <span style="color: #008000;">open</span> <span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;ordre.txt&quot;</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'w'</span><span style="color: black;">&#41;</span> <span style="color: #ff7700;font-weight:bold;">as</span> base:
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">for</span> numero <span style="color: #ff7700;font-weight:bold;">in</span> tous_les_numeros:
&nbsp;
        base.<span style="color: black;">write</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;{0},&quot;</span>.<span style="color: black;">format</span><span style="color: black;">&#40;</span>numero<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>Et dont le contenu est juste :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #000000;">1798</span>,<span style="color: #000000;">915</span>,<span style="color: #000000;">1402</span>,<span style="color: #000000;">1032</span>,<span style="color: #000000;">507</span>,<span style="color: #000000;">112</span>,<span style="color: #000000;">1098</span>,<span style="color: #000000;">600</span>,<span style="color: #000000;">323</span>,<span style="color: #000000;">787</span>,<span style="color: #000000;">1435</span>,<span style="color: #000000;">200</span>,<span style="color: #000000;">774</span>,<span style="color: #000000;">33</span>,<span style="color: #000000;">1419</span>,<span style="color: #000000;">106</span>,<span style="color: #000000;">1836</span>... etc</pre></td></tr></table></div>

<p>Enfin, voici le script final, qui tweete donc toutes les 3,14 heures un des 4992 Super-Héros du Net.</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #808080; font-style: italic;"># -*- coding: utf8 -*-</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Ce script permet d'envoyer un tweet avec une image toutes les 3,14 heures</span>
<span style="color: #808080; font-style: italic;"># Il récupère dans une liste le numéro de l'image a envoyer,</span>
<span style="color: #808080; font-style: italic;"># et enregistre le nombre de tweets déjà postés</span>
<span style="color: #808080; font-style: italic;"># pour pouvoir changer d'image à la prochaine exécution</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">os</span>
<span style="color: #ff7700;font-weight:bold;">from</span> twython <span style="color: #ff7700;font-weight:bold;">import</span> Twython
<span style="color: #ff7700;font-weight:bold;">from</span> <span style="color: #dc143c;">time</span> <span style="color: #ff7700;font-weight:bold;">import</span> sleep
&nbsp;
<span style="color: #808080; font-style: italic;"># Clef d'authentification à obtenir sur https://dev.twitter.com</span>
APP_KEY <span style="color: #66cc66;">=</span> <span style="color: #483d8b;">&quot;votre petite clef-clef à vous&quot;</span>
APP_SECRET <span style="color: #66cc66;">=</span> <span style="color: #483d8b;">&quot;une autre petite clef-clef&quot;</span>
OAUTH_TOKEN <span style="color: #66cc66;">=</span> <span style="color: #483d8b;">&quot;encore une petite clef-clef&quot;</span>
OAUTH_TOKEN_SECRET <span style="color: #66cc66;">=</span> <span style="color: #483d8b;">&quot;enfin, une dernière petite clef-clef&quot;</span>
&nbsp;
twitter <span style="color: #66cc66;">=</span> Twython<span style="color: black;">&#40;</span>APP_KEY<span style="color: #66cc66;">,</span> APP_SECRET<span style="color: #66cc66;">,</span> OAUTH_TOKEN<span style="color: #66cc66;">,</span> OAUTH_TOKEN_SECRET<span style="color: black;">&#41;</span>
&nbsp;
ordre <span style="color: #66cc66;">=</span> <span style="color: black;">&#91;</span><span style="color: black;">&#93;</span>
combien_deja_poste <span style="color: #66cc66;">=</span> <span style="color: #ff4500;">0</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Récupère le répertoire courant</span>
chemin_dossier <span style="color: #66cc66;">=</span> <span style="color: #dc143c;">os</span>.<span style="color: black;">path</span>.<span style="color: black;">dirname</span><span style="color: black;">&#40;</span><span style="color: #dc143c;">os</span>.<span style="color: black;">path</span>.<span style="color: black;">realpath</span><span style="color: black;">&#40;</span>__file__<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>+<span style="color: #483d8b;">&quot;/&quot;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> envoie_moi_donc_un_tweet_avec_une_image_de_Super_Heros_du_Net<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
&nbsp;
    <span style="color: #808080; font-style: italic;"># Récupère l'ordre des images à poster</span>
    <span style="color: #ff7700;font-weight:bold;">with</span> <span style="color: #008000;">open</span> <span style="color: black;">&#40;</span>chemin_dossier+<span style="color: #483d8b;">&quot;ordre.txt&quot;</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'r'</span><span style="color: black;">&#41;</span> <span style="color: #ff7700;font-weight:bold;">as</span> contenu:
&nbsp;
            ordre <span style="color: #66cc66;">=</span> contenu.<span style="color: #dc143c;">readline</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>.<span style="color: black;">rstrip</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'<span style="color: #000099; font-weight: bold;">\n</span>'</span><span style="color: black;">&#41;</span>.<span style="color: black;">split</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;,&quot;</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># Récupère le nombre d'images déjà postées</span>
    <span style="color: #ff7700;font-weight:bold;">with</span> <span style="color: #008000;">open</span> <span style="color: black;">&#40;</span>chemin_dossier+<span style="color: #483d8b;">&quot;deja_poste.txt&quot;</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'r'</span><span style="color: black;">&#41;</span> <span style="color: #ff7700;font-weight:bold;">as</span> contenu:
&nbsp;
        combien_deja_poste <span style="color: #66cc66;">=</span> <span style="color: #008000;">int</span><span style="color: black;">&#40;</span>contenu.<span style="color: #dc143c;">readline</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>.<span style="color: black;">rstrip</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'<span style="color: #000099; font-weight: bold;">\n</span><span style="color: #000099; font-weight: bold;">\r</span>'</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># Récupère le numéro de l'image</span>
    numero <span style="color: #66cc66;">=</span> <span style="color: #008000;">int</span><span style="color: black;">&#40;</span>ordre<span style="color: black;">&#91;</span>combien_deja_poste<span style="color: black;">&#93;</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># Construit le chemin vers cette image</span>
    <span style="color: #808080; font-style: italic;"># Sachant que le dossier AllStar contient les 4992 Super-Héros du Net</span>
    chemin_image <span style="color: #66cc66;">=</span> chemin_dossier+<span style="color: #483d8b;">&quot;AllStar/SuperHeros-{0}.png&quot;</span>.<span style="color: black;">format</span><span style="color: black;">&#40;</span>numero<span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># Charge l'image</span>
    image <span style="color: #66cc66;">=</span> <span style="color: #008000;">open</span><span style="color: black;">&#40;</span>chemin_image<span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'rb'</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># Forme le texte du tweet</span>
    texte <span style="color: #66cc66;">=</span> <span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;Voici le Super-Héros du Net n°{0}<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span>
             <span style="color: #483d8b;">&quot;Si ce n'est pas déjà fait, aidez-le, lui et ses 4992 amis<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span>
             <span style="color: #483d8b;">&quot;soutien.laquadrature.net&quot;</span><span style="color: black;">&#41;</span>.<span style="color: black;">format</span><span style="color: black;">&#40;</span>numero+<span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># Envoie le tweet composé d'un texte et d'une image</span>
    twitter.<span style="color: black;">update_status_with_media</span><span style="color: black;">&#40;</span>status<span style="color: #66cc66;">=</span>texte<span style="color: #66cc66;">,</span> media<span style="color: #66cc66;">=</span>image<span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># Met à jour le nombre d'images déjà postées</span>
    <span style="color: #ff7700;font-weight:bold;">with</span> <span style="color: #008000;">open</span> <span style="color: black;">&#40;</span>chemin_dossier+<span style="color: #483d8b;">&quot;deja_poste.txt&quot;</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'w'</span><span style="color: black;">&#41;</span> <span style="color: #ff7700;font-weight:bold;">as</span> contenu:
&nbsp;
        contenu.<span style="color: black;">write</span><span style="color: black;">&#40;</span><span style="color: #008000;">str</span><span style="color: black;">&#40;</span>combien_deja_poste + <span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">while</span> <span style="color: #008000;">True</span>:
&nbsp;
    envoie_moi_donc_un_tweet_avec_une_image_de_Super_Heros_du_Net<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># Patiente pendant les 3,14 heures, soit  les 11 304 secondes</span>
    sleep<span style="color: black;">&#40;</span><span style="color: #ff4500;">11304</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># Le script plantera dans 2 ans quand les 4992 Super-Héros du Net</span>
    <span style="color: #808080; font-style: italic;"># aurons tous été postés, et c'est très bien ainsi...</span></pre></td></tr></table></div>

<p>Et voilà, il ne reste plus qu&#8217;à choper 10 Millions de followers sur <a href="https://twitter.com/4992SuperHeros">ce compte</a> et à espérer que 3,14% d&#8217;entre eux filent 10€ à LQDN pour que l&#8217;on puisse augmenter les chances de répondre positivement à la question posée dans le titre.<br />
Une simple formalité&#8230;</p>
<p>Je précise que La Quadrature n&#8217;a absolument rien à voir avec ce compte Twitter, c&#8217;était juste l&#8217;occasion pour moi de pondre un article de plus ici tout en soutenant une cause qui me tient hackeur (humour).</p>
<p>À la prochaine&#8230;</p>
<p><em>Information complémentaire : </em><br />
Le Monde en date du 12 août &#8211; <a href="http://www.lemonde.fr/economie/article/2014/08/12/pres-d-un-compte-twitter-sur-10-est-alimente-par-un-robot_4470542_3234.html?xtmc=robot_twitter&amp;xtcr=1">Près d&#8217;un compte Twitter sur 10 est alimenté automatiquement</a></p>


feed_id: http://sametmax.com/?p=12237
title: 0bin a été migré
uri: 0bin-a-été-migré
url: http://sametmax.com/0bin-a-ete-migre/
content:
<p>Vous vous souvenez de <a href="http://sametmax.com/0bin-implementation-python-de-zerobin-pastebin-chiffre-cote-client/">0bin, le paste bin chiffré</a> ? Il est de nouveau en ligne sur <a href="http://0bin.net/">0bin.net</a>.</p>
<p>Je suis en train de copier tous les pastes en ce moment, et il y en a  28436 donc rsync rame un peu (j&#8217;ai fait l&#8217;erreur de le faire avec scp au début&#8230;) du coup tous les pastes ne seront pas là instantanément, mais au final, on les retrouvera tous.</p>
<p>Bref, on répare doucement mais sûrement.</p>


feed_id: http://sametmax.com/?p=12242
title: Multiboards a été migré
uri: Multiboards-a-été-migré
url: http://sametmax.com/multiboards-a-ete-migre/
content:
<p><a href="http://multiboards.net/">multiboards.net</a>, la page Web qu&#8217;on trempe dans son café, a été migrée. Comme il n&#8217;y a aucune donnée associée, ben, le truc n&#8217;a pas bougé, dont vous le retrouverez tel qu&#8217;avant.</p>
<p>Plusieurs personnes nous ont demandé le code source. La raison pour laquelle il n&#8217;est pas publié, c&#8217;est que c&#8217;est un amas de code vraiment peu ragoutant, et qu&#8217;il faudrait vraiment le nettoyer pour éviter que la honte ne s&#8217;abatte sur nous.</p>
<p>Max voudrait en faire un truc personnalisable, avec des widgets, et tout, à la netwibes mais en plus simple. Je pense que ça n&#8217;arrivera jamais :)</p>


feed_id: http://sametmax.com/?p=12248
title: Passer d&#8217;un clé Putty (ppk) à une clé OpenSSH
uri: Passer-d-un-clé-Putty-(ppk)-à-une-clé-OpenSSH
url: http://sametmax.com/passer-dun-cle-putty-ppk-a-une-cle-openssh/
content:
<p>Cas d&#8217;école, mon client me donne la clé pour accéder à son instance Amazon (bouh !) et il me file une clé Putty puisqu&#8217;il est sous Windows. </p>
<p>Heureusement, Putty existe aussi sous nunux. Par exemple sous Ubuntu :</p>
<pre>sudo apt-get install putty-tools</pre>
<p>Et il embarque tout ce qu&#8217;il faut pour convertir sa clé :</p>
<pre>
puttygen cle.ppk -O public-openssh -o nouvelle_cle.pub
puttygen cle.ppk -O private-openssh -o nouvelle_cle</pre>
<p>Y a plus qu&#8217;à mettre dans son dossier <code>.ssh</code>. En prime, je rajoute généralement ça dans <code>.ssh/config</code> :</p>
<pre>Host ip ou domaine
HostName ip ou domaine
User username pour le server
IdentityFile ~/.ssh/nouvelle_cle</pre>
<p>Comme ça pas besoin de sélectionner la clé manuellement à chaque connexion, si SSH voit cette IP, il me prend la bonne clé.</p>
<p>Mon dossier .ssh est un simple lien vers le vrai dossier dans la partition <a href="http://sametmax.com/eviter-davoir-la-queue-a-lair-en-publique-avec-truecrypt/">Truecrypt</a>. Malgré la disparition du projet, j&#8217;ai pas trouvé mieux.</p>


feed_id: http://sametmax.com/?p=12251
title: Accélérer les listings de l&#8217;admin Django avec beaucoup de ForeignKeys
uri: Accélérer-les-listings-de-l-admin-Django-avec-beaucoup-de-ForeignK
url: http://sametmax.com/accelerer-les-listings-de-ladmin-django-avec-beaucoup-de-foreignkeys/
content:
<p>Je pensais que ces astuces étaient très connues, mais quand j&#8217;en ai eu besoin, j&#8217;ai galéré pour mettre la main dessus. Du coup blogage, blogation, blogitude.</p>
<p>L&#8217;admin Django permet de faire automatiquement un listing des objets voulus afin de les modifier. Si un modèle a une ForeignKey et qu&#8217;on définit le champ en <code>list_editable</code>, Django va pondre un drop down pour choisir parmi les relations possibles.</p>
<p>Or, le framework fait une requête <strong>pour chaque objet de la liste</strong>. Si vous avez deux ForeignKeys sur votre modèle et 20 objets (valeur par défaut) dans la liste, ça vous fait donc 40 queries, juste pour afficher ces deux drop down. Doh.</p>
<p>On peut néanmoins forcer Django à cacher le résultat de la première requête, réduisant ainsi le compte à 1, avec cette étrange astuce d&#8217;une mère au foyer (consultants hate her !) :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">class</span> VotreClasseAdmin<span style="color: black;">&#40;</span>admin.<span style="color: black;">ModelAdmin</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># Cette méthode est appelée pour créer le champ de formulaire de pour</span>
    <span style="color: #808080; font-style: italic;"># chaque objet</span>
    <span style="color: #ff7700;font-weight:bold;">def</span> formfield_for_dbfield<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: #66cc66;">,</span> db_field<span style="color: #66cc66;">,</span> **kwargs<span style="color: black;">&#41;</span>:
&nbsp;
        request <span style="color: #66cc66;">=</span> kwargs<span style="color: black;">&#91;</span><span style="color: #483d8b;">'request'</span><span style="color: black;">&#93;</span>
        formfield <span style="color: #66cc66;">=</span> <span style="color: #008000;">super</span><span style="color: black;">&#40;</span>ProductPageAdmin<span style="color: #66cc66;">,</span> <span style="color: #008000;">self</span><span style="color: black;">&#41;</span>.<span style="color: black;">formfield_for_dbfield</span><span style="color: black;">&#40;</span>db_field<span style="color: #66cc66;">,</span> **kwargs<span style="color: black;">&#41;</span>
&nbsp;
        <span style="color: #808080; font-style: italic;"># Si le champ est editable dans la liste</span>
        <span style="color: #ff7700;font-weight:bold;">if</span> db_field.<span style="color: black;">name</span> <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">self</span>.<span style="color: black;">list_editable</span> <span style="color: #ff7700;font-weight:bold;">and</span> <span style="color: #008000;">hasattr</span><span style="color: black;">&#40;</span>formfield<span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'choices'</span><span style="color: black;">&#41;</span>:
&nbsp;
            <span style="color: #808080; font-style: italic;"># On tente de récupérer la query en cache</span>
            cache_attr_name <span style="color: #66cc66;">=</span> <span style="color: #483d8b;">'_%s_cache'</span> % db_field.<span style="color: black;">name</span>
            choices_cache <span style="color: #66cc66;">=</span> <span style="color: #008000;">getattr</span><span style="color: black;">&#40;</span>request<span style="color: #66cc66;">,</span> cache_attr_name<span style="color: black;">&#41;</span>
            <span style="color: #ff7700;font-weight:bold;">if</span> choices_cache <span style="color: #ff7700;font-weight:bold;">is</span> <span style="color: #ff7700;font-weight:bold;">not</span> <span style="color: #008000;">None</span>:
                formfield.<span style="color: black;">choices</span> <span style="color: #66cc66;">=</span> choices_cache
&nbsp;
            <span style="color: #808080; font-style: italic;"># Pas de cache, on force Django à faire la query en accédant</span>
            <span style="color: #808080; font-style: italic;"># au descripteur .choices et on met le resultat</span>
            <span style="color: #808080; font-style: italic;"># en cache</span>
            <span style="color: #ff7700;font-weight:bold;">else</span>:
                <span style="color: #008000;">setattr</span><span style="color: black;">&#40;</span>request<span style="color: #66cc66;">,</span> cache_attr_name<span style="color: #66cc66;">,</span> formfield.<span style="color: black;">choices</span><span style="color: black;">&#41;</span>
&nbsp;
        <span style="color: #808080; font-style: italic;"># On retourne le champ de notre formulaire avec sa valeur mise</span>
        <span style="color: #808080; font-style: italic;"># en cache</span>
        <span style="color: #ff7700;font-weight:bold;">return</span> formfield</pre></td></tr></table></div>

<p>Malheureusement, il peut arriver qu&#8217;il y ait tellement d&#8217;objets que c&#8217;est votre navigateur qui panique. En effet, si vous avez un modèle <code>Promotion</code> avec un lien vers un modèle <code>Produit</code> et que vous avez 5000 produits en base, vous allez créer 20 <code>&lt;select&gt;</code> avec 5000 <code>&lt;options&gt;</code> dedans. 100000 balises dans une page, ça peut faire mal.</p>
<p>Dans ce cas, il vaut mieux désactiver la possibilité de faire un drop down, et mettre un champ text à la place dans lequel on entre un ID en utilisant :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">class</span> VotreClasseAdmin<span style="color: black;">&#40;</span>admin.<span style="color: black;">ModelAdmin</span><span style="color: black;">&#41;</span>
&nbsp;
     raw_id_fields <span style="color: #66cc66;">=</span> <span style="color: black;">&#40;</span><span style="color: #483d8b;">'nom_de_votre_champ'</span><span style="color: #66cc66;">,</span><span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>Django n&#8217;est pas chien, et vous mettra un petit bouton en forme de loupe pour chercher l&#8217;ID dont vous avez besoin.</p>
<p>Si vous avez beaucoup de ForeignKey <strong>non éditables</strong> (<code>readonly_fields</code>), vous pouvez aussi vous fendre d&#8217;un <code>select_related</code> :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">class</span> VotreClasseAdmin<span style="color: black;">&#40;</span>admin.<span style="color: black;">ModelAdmin</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> queryset<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: #66cc66;">,</span> request<span style="color: black;">&#41;</span>:
        <span style="color: #808080; font-style: italic;"># On filtre le queryset que Django va utiliser pour populer la liste</span>
        <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">super</span><span style="color: black;">&#40;</span>MyAdmin<span style="color: #66cc66;">,</span> <span style="color: #008000;">self</span><span style="color: black;">&#41;</span>.<span style="color: black;">queryset</span><span style="color: black;">&#40;</span>request<span style="color: black;">&#41;</span>.<span style="color: black;">select_related</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'myfield'</span><span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>Ça ne marche que sur les non éditables, car pour eux Django ne créé pas de champ de formulaire.</p>


feed_id: http://sametmax.com/?p=12261
title: Trouver ce qui prend de la place en ligne de commande
uri: Trouver-ce-qui-prend-de-la-place-en-ligne-de-commande
url: http://sametmax.com/trouver-ce-qui-prend-de-la-place-en-ligne-de-commande/
content:
<p>Windows a l&#8217;excellent WindDirStats, et Gnome a Baobab. Mais régulièrement je suis en SSH sur un server je lance <code>df</code> pour voir comment vont les disques. La vérité c&#8217;est que ceux avec un monitoring installés ne sont pas la majorité dans mes missions.</p>
<p>À un moment ou un autre, une partition est pleine. Et une fois qu&#8217;on a vidé <code>/var/log</code> et que le taux de remplissage ne semble pas baisser, il faut enquêter.</p>
<p>En général, je recherche sur le net une incantation magique du genre :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #666666; font-style: italic;"># trouver les fichiers qui prennent le plus de place</span>
<span style="color: #c20cb9; font-weight: bold;">find</span> . <span style="color: #660033;">-type</span> f <span style="color: #660033;">-print0</span> <span style="color: #000000; font-weight: bold;">|</span> <span style="color: #c20cb9; font-weight: bold;">xargs</span> <span style="color: #660033;">-0</span> <span style="color: #c20cb9; font-weight: bold;">du</span> <span style="color: #000000; font-weight: bold;">|</span> <span style="color: #c20cb9; font-weight: bold;">sort</span> <span style="color: #660033;">-n</span> <span style="color: #000000; font-weight: bold;">|</span> <span style="color: #c20cb9; font-weight: bold;">tail</span> <span style="color: #660033;">-10</span> <span style="color: #000000; font-weight: bold;">|</span> <span style="color: #c20cb9; font-weight: bold;">cut</span> <span style="color: #660033;">-f2</span> <span style="color: #000000; font-weight: bold;">|</span> <span style="color: #c20cb9; font-weight: bold;">xargs</span> -I<span style="color: #7a0874; font-weight: bold;">&#123;</span><span style="color: #7a0874; font-weight: bold;">&#125;</span> <span style="color: #c20cb9; font-weight: bold;">du</span> <span style="color: #660033;">-sh</span> <span style="color: #7a0874; font-weight: bold;">&#123;</span><span style="color: #7a0874; font-weight: bold;">&#125;</span>
<span style="color: #666666; font-style: italic;"># trouver les dossiers qui prennent le plus de place</span>
<span style="color: #c20cb9; font-weight: bold;">find</span> . <span style="color: #660033;">-type</span> d <span style="color: #660033;">-print0</span> <span style="color: #000000; font-weight: bold;">|</span> <span style="color: #c20cb9; font-weight: bold;">xargs</span> <span style="color: #660033;">-0</span> <span style="color: #c20cb9; font-weight: bold;">du</span> <span style="color: #000000; font-weight: bold;">|</span> <span style="color: #c20cb9; font-weight: bold;">sort</span> <span style="color: #660033;">-n</span> <span style="color: #000000; font-weight: bold;">|</span> <span style="color: #c20cb9; font-weight: bold;">tail</span> <span style="color: #660033;">-10</span> <span style="color: #000000; font-weight: bold;">|</span> <span style="color: #c20cb9; font-weight: bold;">cut</span> <span style="color: #660033;">-f2</span> <span style="color: #000000; font-weight: bold;">|</span> <span style="color: #c20cb9; font-weight: bold;">xargs</span> -I<span style="color: #7a0874; font-weight: bold;">&#123;</span><span style="color: #7a0874; font-weight: bold;">&#125;</span> <span style="color: #c20cb9; font-weight: bold;">du</span> <span style="color: #660033;">-sh</span> <span style="color: #7a0874; font-weight: bold;">&#123;</span><span style="color: #7a0874; font-weight: bold;">&#125;</span></pre></td></tr></table></div>

<p>Puis je me souviens qu&#8217;il y a <code>du</code>, alors je commence à faire un truc comme ça :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #c20cb9; font-weight: bold;">du</span> <span style="color: #660033;">-a</span> . <span style="color: #000000; font-weight: bold;">|</span> <span style="color: #c20cb9; font-weight: bold;">sort</span> <span style="color: #660033;">-n</span> <span style="color: #660033;">-r</span> <span style="color: #000000; font-weight: bold;">|</span> <span style="color: #c20cb9; font-weight: bold;">head</span> <span style="color: #660033;">-n</span> <span style="color: #000000;">10</span></pre></td></tr></table></div>

<p>Mais un jour je suis tombé sur un post d&#8217;un forum disant que je me cassais les couilles pour rien, et qu&#8217;utiliser <code>ncdu</code> était plus simple. Sous Ubuntu :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #c20cb9; font-weight: bold;">sudo</span> <span style="color: #c20cb9; font-weight: bold;">apt-get install</span> ncdu
ncdu</pre></td></tr></table></div>

<p>Et effectivement, je me cassais les couilles pour rien, c&#8217;est plus simple.</p>


feed_id: http://sametmax.com/?p=12269
title: Travailler sur une lib externe à votre projet proprement en Python
uri: Travailler-sur-une-lib-externe-à-votre-projet-proprement-en-Python
url: http://sametmax.com/travailler-sur-une-lib-externe-a-votre-projet-proprement-en-python/
content:
<p>Quand on a une lib externe en dépendance à son projet, on veut être capable de l&#8217;importer MAIS pouvoir en modifier le code.</p>
<p>L&#8217;installer avec <code>pip</code> ou python <code>setup.py install</code> va copier le code dans le dossier <code>site-packages</code> et ce n&#8217;est pas ce que l&#8217;on veut car ça oblige à refaire l&#8217;installation à chaque modif.</p>
<p>Le mettre dans un dossier &#8220;libs&#8221; qu&#8217;on ajoute au <code>PYTHON PATH</code> ou pire, ajouter chaque dépendance au <code>PYTHON PATH</code> n&#8217;est pas une solution qu&#8217;on est fier d&#8217;exhiber au hackerspace du coin.</p>
<p>On s&#8217;en remet donc généralement à un symlink, sans savoir qu&#8217;il existe en fait un outil fait pour ça :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="bash" style="font-family:monospace;">python setup.py develop</pre></td></tr></table></div>

<p>Cette commande va ajouter des entrées spéciales dans des fichiers placés dans <code>site-packages</code> qui vont vous permettre d&#8217;utiliser votre lib comme si elle était installée. Mais en vérité il va chercher le code dans votre dossier de dev, donc si vous modifiez le code, vous avez toujours la version de votre lib la plus fraîche.</p>
<p>Une fois qu&#8217;on a une lib stable, on peut retirer ce lien avec :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="bash" style="font-family:monospace;">python setup.py develop <span style="color: #660033;">--uninstall</span></pre></td></tr></table></div>

<p>Et installer la lib normalement.</p>
<p>Notez que tout ceci ne fonctionne que si le <code>setup.py</code> utilise <code>setuptools</code> et non <code>distutils</code> qui provoque l&#8217;erreur <em>error: invalid command &#8216;develop&#8217;</em>.</p>
<p>Comme <code>setuptools</code> inclut maintenant le meilleur de <code>distutils</code>, on peut remplacer :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">from</span> <span style="color: #dc143c;">distutils</span>.<span style="color: black;">core</span> <span style="color: #ff7700;font-weight:bold;">import</span> setup</pre></td></tr></table></div>

<p>Par :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">from</span> setuptools <span style="color: #ff7700;font-weight:bold;">import</span> setup</pre></td></tr></table></div>

<p>Sans soucis.</p>
<p><code>pip</code> vient lui aussi avec un outil pour ça en la forme du flag <code>-e</code> qui fait exactement la même chose. Exemple :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="bash" style="font-family:monospace;">pip <span style="color: #c20cb9; font-weight: bold;">install</span> <span style="color: #660033;">-e</span> <span style="color: #000000; font-weight: bold;">/</span>chemin<span style="color: #000000; font-weight: bold;">/</span>local<span style="color: #000000; font-weight: bold;">/</span>vers<span style="color: #000000; font-weight: bold;">/</span>projet</pre></td></tr></table></div>

<p>Cela fonctionne comme pour <code>python setup.py develop --uninstall</code> mais on bénéficie de tous les goodies de <code>pip</code> en prime.</p>
<p>Néanmoins, <code>pip</code> pousse plus loin l&#8217;automatisation. Si vous faites <code>pip install -e</code> sur un repo distant, il va également cloner pour vous le code.</p>
<p>Ex :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="bash" style="font-family:monospace;">pip <span style="color: #c20cb9; font-weight: bold;">install</span> <span style="color: #660033;">-e</span> <span style="color: #c20cb9; font-weight: bold;">git</span>+https:<span style="color: #000000; font-weight: bold;">//</span><span style="color: #c20cb9; font-weight: bold;">git</span><span style="color: #000000; font-weight: bold;">@</span>github.com<span style="color: #000000; font-weight: bold;">/</span>sametmax<span style="color: #000000; font-weight: bold;">/</span>minibelt.git<span style="color: #666666; font-style: italic;">#egg=minibelt</span></pre></td></tr></table></div>

<p>Et on retrouvera un clone du projet dans <code>/chemin/vers/virtualenv/src/</code> qui sera importable, modifiable et pushable. Le résultat est automatisable, puisque <code>pip freeze</code> le prend en compte:</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="bash" style="font-family:monospace;">$ pip freeze
<span style="color: #007800;">argparse</span>==1.2.1
<span style="color: #660033;">-e</span> <span style="color: #c20cb9; font-weight: bold;">git</span>+https:<span style="color: #000000; font-weight: bold;">//</span><span style="color: #c20cb9; font-weight: bold;">git</span><span style="color: #000000; font-weight: bold;">@</span>github.com<span style="color: #000000; font-weight: bold;">/</span>sametmax<span style="color: #000000; font-weight: bold;">/</span>minibelt.git<span style="color: #000000; font-weight: bold;">@</span>b898155b40d7de73cc404db7d274128f2b2fc330<span style="color: #666666; font-style: italic;">#egg=minibelt-master</span>
<span style="color: #007800;">wsgiref</span>==0.1.2</pre></td></tr></table></div>

<p>L&#8217;URL est assez batarde à trouver par contre, car elle doit toujours finir par <code>#egg=nom-du-projet</code> et commencer par un double protocole, celui du VCS et celui du transport.</p>
<p>P.S: j&#8217;ai remis la coloration syntaxique et les iframes (donc la musique). J&#8217;aime bien ce thème là, mais la header chie sa mère. Est-ce que vous l&#8217;aimez suffisamment pour que je me casse le cul à le réparer ?</p>


feed_id: http://sametmax.com/?p=12353
title: Le compteur mal connu : l&#8217;HyperLogLog
uri: Le-compteur-mal-connu-l-HyperLogLog
url: http://sametmax.com/le-compteur-mal-connu-lhyperloglog/
content:
<p>Non, <a href="https://en.wikipedia.org/wiki/HyperLogLog">ce n&#8217;est pas une faute de frappe</a>. l&#8217;HyperLogLog est un algo qui permet de compter approximativement des éléments uniques en prenant très peu de mémoire.</p>
<p>Prenez par exemple un compteur d&#8217;IP uniques. En Python, on l&#8217;implémenterait en mettant les adresses IP dans un <code>set()</code> (puisqu&#8217;ils éliminent les doublons) et pour obtenir le nombre d&#8217;IP uniques, on ferait <code>len()</code> sur le <code>set</code>.</p>
<p>Une bonne stratégie, performante (les sets sont très rapides pour ce genre d&#8217;usage), simple, mais avec un défaut : la taille du <code>set</code> ne va cesser d&#8217;augmenter au fur et à mesure qu&#8217;on le remplit d&#8217;IP puisqu&#8217;il nous faut l&#8217;historique de toutes celles rencontrées pour éviter les doublons.</p>
<p>L&#8217;HyperLogLog répond à cette problématique : il tient un journal probabiliste qui va se remplir au fur et à mesure qu&#8217;on rencontre des nouveaus éléments. On peut ensuite demander au journal combien d&#8217;éléments uniques il a rencontré, et il répond avec une marge d&#8217;erreur.</p>
<p><strong>Avantage </strong>: la taille en mémoire est fixe.<br />
<strong>Désavantage </strong>: le compteur n&#8217;est pas parfaitement précis.</p>
<p>La précision obtenue est dépendante de la place en mémoire, par exemple si on on tolère 1% d&#8217;erreur, le journal prendra au maximum 12kb, permettant de compter jusqu&#8217;à 2^64 items.</p>
<p>Bref, si vous faites juste un compteur à afficher en pied de page de votre site, c&#8217;est un très bon compromis. On peut accepter d&#8217;avoir un peu plus ou un peu moins de visiteurs que la réalité qui s&#8217;affiche, sachant que la stat elle-même n&#8217;est pas vraiment réprésentative de la réalité (IP != de visiteurs uniques).</p>
<p>En Python, il existe une lib (uniquement 2.7 il me semble) pour ça :</p>
<pre lang="bash>pip install hyperloglog</pre>
<p>Et ça s&#8217;utilise très simplement :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #ff7700;font-weight:bold;">import</span> hyperloglog<span style="color: #66cc66;">,</span> <span style="color: #dc143c;">random</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> hll <span style="color: #66cc66;">=</span> hyperloglog.<span style="color: black;">HyperLogLog</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">0.01</span><span style="color: black;">&#41;</span>  <span style="color: #808080; font-style: italic;"># on accepte une erreur de 1%</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> hll.<span style="color: black;">add</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;119.250.66.95&quot;</span><span style="color: black;">&#41;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #008000;">len</span><span style="color: black;">&#40;</span>hll<span style="color: black;">&#41;</span>  
<span style="color: #ff4500;">1</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> hll.<span style="color: black;">add</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;119.250.66.95&quot;</span><span style="color: black;">&#41;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #008000;">len</span><span style="color: black;">&#40;</span>hll<span style="color: black;">&#41;</span>  
<span style="color: #ff4500;">1</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> hll.<span style="color: black;">add</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;219.81.118.147&quot;</span><span style="color: black;">&#41;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #008000;">len</span><span style="color: black;">&#40;</span>hll<span style="color: black;">&#41;</span>  
<span style="color: #ff4500;">2</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #ff7700;font-weight:bold;">for</span> x <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">xrange</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">1000</span><span style="color: black;">&#41;</span>:
... <span style="color: black;">ip</span> <span style="color: #66cc66;">=</span> <span style="color: #483d8b;">&quot;.&quot;</span>.<span style="color: black;">join</span><span style="color: black;">&#40;</span><span style="color: #008000;">str</span><span style="color: black;">&#40;</span><span style="color: #dc143c;">random</span>.<span style="color: black;">randint</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">1</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">255</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span> <span style="color: #ff7700;font-weight:bold;">for</span> x <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">range</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">4</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
... <span style="color: #ff7700;font-weight:bold;">print</span> ip
... <span style="color: black;">hll</span>.<span style="color: black;">add</span><span style="color: black;">&#40;</span>ip<span style="color: black;">&#41;</span>
114.208.49.91
11.72.239.16
67.56.229.66
191.62.59.163
61.104.232.43
110.58.69.141
246.123.30.234
244.246.65.219
98.93.193.114
185.143.143.69
191.177.161.213
...
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #008000;">len</span><span style="color: black;">&#40;</span>hll<span style="color: black;">&#41;</span> <span style="color: #808080; font-style: italic;"># 1000 items unique. Environ :)</span>
<span style="color: #ff4500;">1004</span></pre></td></tr></table></div>

<p>Vous pouvez également profiter de l&#8217;HyperLogLog via une <a href="http://tapoueh.org/blog/2013/02/25-postgresql-hyperloglog">extension PostGres</a> ou en utilisant une version récente de <a href="http://redis.io/commands#hyperloglog">Redis</a>.</p>
<p>La plupart des compteurs sur les sites sont complètement bidons, alors vous, honnête que vous êtes, embrassez l&#8217;approximatif ! C&#8217;est presque la vérité. Presque.</p>


feed_id: http://sametmax.com/?p=12332
title: Restauration des fonctionnalités
uri: Restauration-des-fonctionnalités
url: http://sametmax.com/restauration-des-fonctionnalites/
content:
<p>Après les iframes et la coloration syntaxique, le <a href="http://sametmax.com/contactez-nous/">formulaire de contact</ahref=>, le <a href="http://bridge.suumitsu.eu/?action=display&#038;bridge=TwitterBridge&#038;u=sam_et_max&#038;format=AtomFormat">flux rss des tweets</a> et le <a href="http://sametmax.com/planet-python-fr/">planet Python fr</a> sont de nouveau opérationnels. </p>
<p>Ça me fait penser que si vous connaissez des blogs fr sur Python, proposez les pour le planet.</p>


feed_id: http://sametmax.com/?p=12376
title: Bien nommer ses variables en Python
uri: Bien-nommer-ses-variables-en-Python
url: http://sametmax.com/bien-nommer-ses-variables-en-python/
content:
<blockquote><p>There are only two hard things in Computer Science: cache invalidation and naming things.</p></blockquote>
<p><em>Phil Karlton</em></p>
<p>Utiliser des bons noms est le geste de documentation le plus important d&#8217;un code. Je ne parle pas de bien formater le nom des variables. Pour ça, il y a le PEP8 et ce qu&#8217;il recommande tient en 3 lignes :</p>
<ul>
<li>Le nom des classes en CamelCase</li>
<li>Les (pseudo) constantes en UPPER_CASE</li>
<li>Le reste en snake_case</li>
</ul>
<p>C&#8217;est tout.</p>
<p>Non, je parle de choisir un nom adapté et descriptif.</p>
<p>Le post est long, et vous savez que quand le post est long, je vous mets une musique d&#8217;attente.</p>
<p><span class='embed-youtube' style='text-align:center; display: block;'><iframe class='youtube-player' type='text/html' width='1170' height='689' src='http://www.youtube.com/embed/4TV_128Fz2g?version=3&#038;rel=1&#038;fs=1&#038;showsearch=0&#038;showinfo=1&#038;iv_load_policy=1&#038;wmode=transparent' frameborder='0'></iframe></span></p>
<h2>Explicit is better than implicit</h2>
<p>En Python, il n&#8217;y a pas de déclaration de type. Le nom d&#8217;une variable a donc d&#8217;autant plus d&#8217;importance pour expliquer ce qu&#8217;il y a dedans.</p>
<p>Prenez cet exemple :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;">best <span style="color: #66cc66;">=</span> <span style="color: black;">&#91;</span><span style="color: black;">&#93;</span>
<span style="color: #ff7700;font-weight:bold;">for</span> k<span style="color: #66cc66;">,</span> v <span style="color: #ff7700;font-weight:bold;">in</span> data.<span style="color: black;">items</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">if</span> v <span style="color: #66cc66;">&gt;</span> top:
        best.<span style="color: black;">append</span><span style="color: black;">&#40;</span>k<span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>Quand on lit ce bout de code, on se demande :</p>
<ul>
<li>Best ? Mais best en quoi ?</li>
<li>Que contient data ?</li>
<li>Quel est la nature de top ?</li>
</ul>
<p>Maintenant, avec des noms explicites :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;">best_players <span style="color: #66cc66;">=</span> <span style="color: black;">&#91;</span><span style="color: black;">&#93;</span>
<span style="color: #ff7700;font-weight:bold;">for</span> player<span style="color: #66cc66;">,</span> score <span style="color: #ff7700;font-weight:bold;">in</span> data.<span style="color: black;">items</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">if</span> score <span style="color: #66cc66;">&gt;</span> top_score :
        best_players.<span style="color: black;">append</span><span style="color: black;">&#40;</span>player<span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>On comprend tout de suite de quoi il est question. L&#8217;algo n&#8217;a pas changé, seul le nommage a changé.</p>
<p>Et si on passe à une écriture plus compacte, le gain est encore plus net :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;">best <span style="color: #66cc66;">=</span> <span style="color: black;">&#91;</span>k <span style="color: #ff7700;font-weight:bold;">for</span> k<span style="color: #66cc66;">,</span> v <span style="color: #ff7700;font-weight:bold;">in</span> data.<span style="color: black;">items</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span> <span style="color: #ff7700;font-weight:bold;">if</span> k <span style="color: #66cc66;">&gt;</span> top<span style="color: black;">&#93;</span></pre></td></tr></table></div>

<p>VS</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;">best_players <span style="color: #66cc66;">=</span> <span style="color: black;">&#91;</span>player <span style="color: #ff7700;font-weight:bold;">for</span> player<span style="color: #66cc66;">,</span> score <span style="color: #ff7700;font-weight:bold;">in</span> data.<span style="color: black;">items</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span> <span style="color: #ff7700;font-weight:bold;">if</span> score <span style="color: #66cc66;">&gt;</span> top_score<span style="color: black;">&#93;</span></pre></td></tr></table></div>

<p>Parfois, on veut la concision, mais faute de nommage, on doit se retourner vers les commentaires :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #808080; font-style: italic;"># Get players with the best scores</span>
best <span style="color: #66cc66;">=</span> <span style="color: black;">&#91;</span>k <span style="color: #ff7700;font-weight:bold;">for</span> k<span style="color: #66cc66;">,</span> v <span style="color: #ff7700;font-weight:bold;">in</span> data.<span style="color: black;">items</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span> <span style="color: #ff7700;font-weight:bold;">if</span> k <span style="color: #66cc66;">&gt;</span> top<span style="color: black;">&#93;</span></pre></td></tr></table></div>

<p>Néanmoins, si on doit faire le choix entre commenter et bien nommer, le nommage doit avoir priorité. Le commentaire est important, mais c&#8217;est le dernier recours d&#8217;un code qui n&#8217;est pas explicite. Avoir un code clair doit être l&#8217;objectif premier. Ensuite, seulement, on le commente (abondamment toutefois, faut pas être radin).</p>
<p>Si vous avez suivi, je nomme mes variables en fonction de leur nature, pas leur type. On peut utiliser les règles de l&#8217;orthographe pour encore plus de précision, par exemple le pluriel.</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;">fruits <span style="color: #66cc66;">=</span> <span style="color: black;">&#91;</span><span style="color: #483d8b;">&quot;kiwi&quot;</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">&quot;banane&quot;</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'poire'</span><span style="color: black;">&#93;</span>
<span style="color: #ff7700;font-weight:bold;">for</span> fruit <span style="color: #ff7700;font-weight:bold;">in</span> fruits:
    <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span>fruit<span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>J&#8217;utilise le pluriel pour une liste de données, qui va donc potentiellement contenir plusieurs fruits. Mais j&#8217;utilise un singulier dans la boucle pour le fruit en court.</p>
<p>L&#8217;utilisation d&#8217;adjectifs est aussi le bienvenu :</p>
<p><code>fruits</code> peut devenir, après un traitement <code>filtered_fruits</code>, indiquant que la liste a subit un filtrage. Les mots en &#8220;ed&#8221; en anglais aident beaucoup à la qualification.</p>
<p>On évite au maximum les variables courtes. Certains cas sont néanmoins tolérés. Le premier est l&#8217;utilisation de <code>i</code>, <code>x</code>, <code>y</code>et <code>z</code> pour des indices.</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">for</span> i<span style="color: #66cc66;">,</span> fruit <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">enumerate</span><span style="color: black;">&#40;</span>fruits<span style="color: black;">&#41;</span>:
    <span style="color: #808080; font-style: italic;"># faire un truc</span></pre></td></tr></table></div>

<p>Les indices sont quelque chose de tellement courant en informatique qu&#8217;on ne va pas se gaver à l&#8217;appeler &#8220;indice&#8221; à chaque fois.</p>
<p>Le second est dans le cadre scientifique. On a souvent des variables pour un algo, des coordonnées, des valeurs géométriques ou mathématiques, qui n&#8217;ont pas de dénomination. Dans ce cas, inutile d&#8217;essayer d&#8217;inventer une nomenclature tordue. Exemple typique, <a href="http://equi4.com/md5/pymd5.py">l&#8217;algo pour pondre un MD5</a>. Mais il faut compenser par des commentaires, sinon on s&#8217;y perd.</p>
<p>Il ne faut pas avoir peur des noms longs. Si, j&#8217;ai un jeu de données, que je filtre plusieurs fois, il est de bon ton de distinguer les différents jeux avec des noms détaillés :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;">sample <span style="color: #66cc66;">=</span> <span style="color: #008000;">range</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">10</span><span style="color: black;">&#41;</span>
squares <span style="color: #66cc66;">=</span> <span style="color: black;">&#91;</span>x * x <span style="color: #ff7700;font-weight:bold;">for</span> x <span style="color: #ff7700;font-weight:bold;">in</span> sample<span style="color: black;">&#93;</span>
even_squares <span style="color: #66cc66;">=</span> <span style="color: black;">&#91;</span>x <span style="color: #ff7700;font-weight:bold;">for</span> x <span style="color: #ff7700;font-weight:bold;">in</span> squares <span style="color: #ff7700;font-weight:bold;">if</span> x % <span style="color: #ff4500;">2</span> <span style="color: #66cc66;">==</span> <span style="color: #ff4500;">0</span><span style="color: black;">&#93;</span>
even_squares_tail <span style="color: #66cc66;">=</span> even_squares<span style="color: black;">&#91;</span>-<span style="color: #ff4500;">3</span>:<span style="color: black;">&#93;</span></pre></td></tr></table></div>

<p>Faire des noms de plus de 10 caractères n&#8217;est pas sale. On est pas sur un tableau des scores d&#8217;une borne d&#8217;arcade des années 80.</p>
<p>J&#8217;utilise bien entendu des noms en anglais, ce qui est toujours préférable, mais si vous devez en mettre en fr, évitez à tout prix les accents malgré la possibilité de les utiliser en Python 3.</p>
<h2>Conventions</h2>
<p>Il existe quelques noms qui sont toujours utilisés de la même façon en Python.</p>
<p><code>self</code> et <code>cls</code> sont les plus connus, en j&#8217;en parle déjà dans <a href="https://duckduckgo.com/l/?kh=-1&#038;uddg=http%3A%2F%2Fsametmax.com%2Fle-guide-ultime-et-definitif-sur-la-programmation-orientee-objet-en-python-a-lusage-des-debutants-qui-sont-rassures-par-les-textes-detailles-qui-prennent-le-temps-de-tout-expliquer-partie-1">le dossier sur la POO</a>.</p>
<p>Il y a <code>args</code> et <code>kwargs</code>, qu&#8217;on utilise avec l&#8217;opérateur splat, dont je parle <a href="https://duckduckgo.com/l/?kh=-1&#038;uddg=http%3A%2F%2Fsametmax.com%2Foperateur-splat-ou-etoile-en-python%2F">ici</a>.</p>
<p>Et puis il y en a de plus discrets.</p>
<p><code>_</code> est utilisé pour une variable qu&#8217;on ignore. Certaines opérations, comme l&#8217;unpacking, supposent la création de plusieurs variables. Si on n&#8217;est pas intéressé par l&#8217;une d&#8217;elles, on peut le signaler. Par exemple, l&#8217;ORM django permet d&#8217;obtenir un objet, et si il n&#8217;existe pas, de le créer. Cette fonction retourne un tuble (objet, bool), l&#8217;élément indiquant si l&#8217;objet a été créé ou non. Si cette information nous intéresse :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #dc143c;">user</span><span style="color: #66cc66;">,</span> created <span style="color: #66cc66;">=</span> User.<span style="color: black;">objects</span>.<span style="color: black;">get_or_create</span><span style="color: black;">&#40;</span>username<span style="color: #66cc66;">=</span><span style="color: #483d8b;">&quot;sam&quot;</span><span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>Si cette information ne nous intéresse pas :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #dc143c;">user</span><span style="color: #66cc66;">,</span> _ <span style="color: #66cc66;">=</span> User.<span style="color: black;">objects</span>.<span style="color: black;">get_or_create</span><span style="color: black;">&#40;</span>username<span style="color: #66cc66;">=</span><span style="color: #483d8b;">&quot;sam&quot;</span><span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>Ainsi le lecteur saura qu&#8217;il peut ignorer cette variable quand il parcourt le code.</p>
<p>Il y a aussi les alias. On ne peut pas utiliser certains noms comme <code>list</code> ou <code>id</code> qui sont des fonctions existantes en Python.</p>
<p>On s&#8217;arrange généralement en trouvant un synonyme, mais si ce n&#8217;est pas pratique, on change une lettre. <code>list</code> devient <code>lst</code> (rappelez vous que <code>list</code> est un nom déjà assez pourri, nommez plutôt le contenu), <code>class</code> devient <code>klass</code>, <code>dict</code> devient <code>dct</code>, etc.</p>
<p>Si on ne peut pas le faire, la convention est de rajouter un underscore à la fin du nom : <code>id</code> devient <code>id_</code>, <code>max</code> devient <code>max_</code>&#8230; Mais faites l&#8217;effort, avant, de chercher un synonyme. Je vois trop souvent des <code>from_</code>/<code>to</code> alors que certains contextes permettent parfaitement de les nommer <code>start</code>/<code>end</code> ou <code>source</code>/<code>destination</code>.</p>
<p>A ne pas confondre avec l&#8217;underscore AVANT le nom, qui est une convention pour dire qu&#8217;une variable ne fait pas partie de l&#8217;API publique.</p>
<p>Ce sont des béquilles, le choix d&#8217;un nom judicieux et clair est toujours préférable, mais ce sont des béquilles utiles.</p>
<h2>Savoir quand nommer</h2>
<p>Au delà de donner un bon nom, il y a le fait de choisir quand il faut nommer, et quand il faut éviter de le faire.</p>
<p>Si seul le résultat final d&#8217;un traitement m&#8217;intéresse, alors, il vaut mieux utiliser une seule variable et mettre le nouveau résultat dedans à chaque fois :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;">fstab <span style="color: #66cc66;">=</span> <span style="color: black;">&#91;</span>line.<span style="color: black;">strip</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span> <span style="color: #ff7700;font-weight:bold;">for</span> line <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">open</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'/etc/fstab'</span><span style="color: black;">&#41;</span> <span style="color: #ff7700;font-weight:bold;">if</span> line<span style="color: black;">&#93;</span>
fstab <span style="color: #66cc66;">=</span> <span style="color: black;">&#91;</span>line.<span style="color: black;">lower</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span> <span style="color: #ff7700;font-weight:bold;">for</span> line <span style="color: #ff7700;font-weight:bold;">in</span> fstab <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #ff7700;font-weight:bold;">not</span> line.<span style="color: black;">startswith</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'#'</span><span style="color: black;">&#41;</span><span style="color: black;">&#93;</span>
fstab <span style="color: #66cc66;">=</span> <span style="color: black;">&#91;</span>line.<span style="color: black;">split</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><span style="color: black;">&#91;</span>:<span style="color: #ff4500;">3</span><span style="color: black;">&#93;</span> <span style="color: #ff7700;font-weight:bold;">for</span> line <span style="color: #ff7700;font-weight:bold;">in</span> fstab<span style="color: black;">&#93;</span></pre></td></tr></table></div>

<p>il faut aussi savoir quand ne pas du tout créer une variable :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;">row <span style="color: #66cc66;">=</span> line.<span style="color: black;">strip</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>.<span style="color: black;">split</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">for</span> col <span style="color: #ff7700;font-weight:bold;">in</span> row:
    <span style="color: #808080; font-style: italic;"># do something</span></pre></td></tr></table></div>

<p>ici, la variable intermédiaire est inutile :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">for</span> col <span style="color: #ff7700;font-weight:bold;">in</span> line.<span style="color: black;">strip</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>.<span style="color: black;">split</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    <span style="color: #808080; font-style: italic;"># do something</span></pre></td></tr></table></div>

<p>L&#8217;inverse est aussi vrai :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">for</span> col <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: black;">&#91;</span><span style="color: #008000;">int</span><span style="color: black;">&#40;</span>x<span style="color: black;">&#41;</span> <span style="color: #ff7700;font-weight:bold;">for</span> x <span style="color: #ff7700;font-weight:bold;">in</span> line.<span style="color: black;">strip</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>.<span style="color: black;">split</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><span style="color: black;">&#93;</span>:
    <span style="color: #808080; font-style: italic;"># do something</span></pre></td></tr></table></div>

<p>La ligne devient beaucoup trop complexe, et ajouter une variable intermédiaire avec un bon nom va améliorer la lisibilité du programme :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;">numeric_col <span style="color: #66cc66;">=</span> <span style="color: black;">&#91;</span><span style="color: #008000;">int</span><span style="color: black;">&#40;</span>x<span style="color: black;">&#41;</span> <span style="color: #ff7700;font-weight:bold;">for</span> x <span style="color: #ff7700;font-weight:bold;">in</span> line.<span style="color: black;">strip</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>.<span style="color: black;">split</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><span style="color: black;">&#93;</span>
<span style="color: #ff7700;font-weight:bold;">for</span> col <span style="color: #ff7700;font-weight:bold;">in</span> numeric_col:
    <span style="color: #808080; font-style: italic;"># do something</span></pre></td></tr></table></div>

<p>On pourrait croire que je précise le type ici en utilisant &#8220;numeric&#8221;, mais je n&#8217;ai pas utilisé integer ou float. J&#8217;ai précisé la nature : des colonnes numériques. Il se trouve que pour des données aussi brutes, la nature se rapproche du type.</p>
<p>Si vous êtes du genre à utiliser des <a href="https://duckduckgo.com/l/?kh=-1&#038;uddg=http%3A%2F%2Fsametmax.com%2Ffonctions-anonymes-en-python-ou-lambda%2F">lambdas</a>, cela s&#8217;applique aussi à vous.</p>
<p>Pour quelque chose de simple, une lambda inline est très lisible :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #008000;">sorted</span><span style="color: black;">&#40;</span>scores.<span style="color: black;">items</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><span style="color: #66cc66;">,</span> key<span style="color: #66cc66;">=</span><span style="color: #ff7700;font-weight:bold;">lambda</span> score: score<span style="color: black;">&#91;</span><span style="color: #ff4500;">1</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>Mais pour quelque chose de complexe, une fonction complète est bien plus adaptée :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">def</span> calculate_rank<span style="color: black;">&#40;</span>score<span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">sum</span><span style="color: black;">&#40;</span>goals <span style="color: #ff7700;font-weight:bold;">for</span> sort<span style="color: #66cc66;">,</span> goal <span style="color: #ff7700;font-weight:bold;">in</span> score<span style="color: black;">&#91;</span><span style="color: #ff4500;">1</span><span style="color: black;">&#93;</span> <span style="color: #ff7700;font-weight:bold;">if</span> sort <span style="color: #66cc66;">==</span> <span style="color: #483d8b;">'A'</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #008000;">sorted</span><span style="color: black;">&#40;</span>scores.<span style="color: black;">items</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><span style="color: #66cc66;">,</span> key<span style="color: #66cc66;">=</span>calculate_rank<span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>Plutôt qu&#8217;un horrible :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #008000;">sorted</span><span style="color: black;">&#40;</span>scores.<span style="color: black;">items</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><span style="color: #66cc66;">,</span> key<span style="color: #66cc66;">=</span><span style="color: #ff7700;font-weight:bold;">lambda</span> x: <span style="color: #008000;">sum</span><span style="color: black;">&#40;</span>g <span style="color: #ff7700;font-weight:bold;">for</span> s<span style="color: #66cc66;">,</span> g <span style="color: #ff7700;font-weight:bold;">in</span> x<span style="color: black;">&#91;</span><span style="color: #ff4500;">1</span><span style="color: black;">&#93;</span> <span style="color: #ff7700;font-weight:bold;">if</span> s <span style="color: #66cc66;">==</span> <span style="color: #483d8b;">'A'</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>Pourquoi je parle de lambda alors qu&#8217;on est sur du nommage ? Parce qu&#8217;une lambda est anonyme, alors qu&#8217;une fonction normale a un nom. Et ce nom exprime l&#8217;action de la fonction. Il documente.</p>
<h2>Habitudes stylistiques</h2>
<p>Ces règles là ne sont pas officielles, mais j&#8217;ai pu les constater dans nombre de bons codes.</p>
<p>La nom d&#8217;une fonction/méthode est aussi important, sinon plus, que le nom d&#8217;une variable. Il n&#8217;est pas rare que j&#8217;écrive des fonctions avec des noms bien dodus comme :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">def</span> get_last_downloaded_shemale_vids<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>Si on oublie la docstring, on a déjà une bonne idée de ce que cette fonction fait. Cela n&#8217;empêche pas de docstringuer quand même pour annoncer des subtilités sur les types, les potentiels side effects, des choses à savoir sur le temps d&#8217;exécution, le format, les perfs, etc.</p>
<p>Mais il arrive souvent qu&#8217;une fonction ne fasse pas quelque chose d&#8217;aussi concret. Prenez par exemple une fonction dont le but est de sluggifier les strings d&#8217;une list.</p>
<p>Si la fonction transforme la liste, on va utiliser un verbe dans le nom :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;">slugify_items<span style="color: black;">&#40;</span>data<span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>Si par contre la fonction retourne une liste avec les éléments modifiés, on va utiliser le participe passé :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;">data <span style="color: #66cc66;">=</span> slugified_items<span style="color: black;">&#40;</span>data<span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>C&#8217;est subtil, mais la sémantique est différente. Dans le premier cas, on s&#8217;attend à un effet de bord. Dans le second cas, on s&#8217;attend à une nouvelle liste, ou comme souvent en Python, à un <a href="http://sametmax.com/comment-utiliser-yield-et-les-generateurs-en-python/">générateur</a>.</p>
<p>Quand on a affaire à une méthode en Python, on utilise rarement le préfixe <code>get_</code>. Personnellement je l&#8217;utilise parfois pour des actions complexes, ou des méthodes de classe.</p>
<p>Mais généralement, on préférera utiliser directement le nom de ce qu&#8217;on veut récupérer. Exemple :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;">comments <span style="color: #66cc66;">=</span> blog_post.<span style="color: black;">get_comments</span><span style="color: black;">&#40;</span>spam<span style="color: #66cc66;">=</span><span style="color: #008000;">False</span><span style="color: black;">&#41;</span> <span style="color: #808080; font-style: italic;"># NON</span>
comments <span style="color: #66cc66;">=</span> blog_post.<span style="color: black;">comments</span><span style="color: black;">&#40;</span>spam<span style="color: #66cc66;">=</span><span style="color: #008000;">False</span><span style="color: black;">&#41;</span> <span style="color: #808080; font-style: italic;"># Oui</span></pre></td></tr></table></div>

<p>Si on n&#8217;a pas besoin de passer de paramètre, alors une <a href="http://sametmax.com/le-guide-ultime-et-definitif-sur-la-programmation-orientee-objet-en-python-a-lusage-des-debutants-qui-sont-rassures-par-les-textes-detailles-qui-prennent-le-temps-de-tout-expliquer-partie-2/">property</a> est plus appropriée :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;">comments <span style="color: #66cc66;">=</span> blog_post.<span style="color: black;">comments</span> <span style="color: #808080; font-style: italic;"># Ouiiiiiiiiiiiiiii</span></pre></td></tr></table></div>

<p>J&#8217;en profite pour faire remarquer qu&#8217;il est très classe de prononcer plusieurs fois très vite &#8220;sans paramètre, une propriété est plus appropriée&#8221;.</p>
<p>Enfin, il arrive qu&#8217;on ait besoin de spécifier des rôles techniques et des interactions entre plusieurs bouts de code : hiérarchie, composition, dépendances, etc. Ce sont les choses les plus compliquées à comprendre quand on lit du code : voir le tableau au complet, ce qui lie les différents blocs.</p>
<p>Il ne faut pas hésiter à nommer ses éléments pour cela. Apprendre le nom des design patterns aide beaucoup, mais même si on n&#8217;est pas top moumoute niveau vocabulaire, on peut faire des choses aussi simple que :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">class</span> BaseAuthenticator<span style="color: black;">&#40;</span><span style="color: #008000;">object</span><span style="color: black;">&#41;</span>:
    <span style="color: #808080; font-style: italic;">#...</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">class</span> PwdAuthenticator<span style="color: black;">&#40;</span>BaseAuthenticator<span style="color: black;">&#41;</span>:
    <span style="color: #808080; font-style: italic;">#...</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">class</span> KeyAuthenticator<span style="color: black;">&#40;</span>BaseAuthenticator<span style="color: black;">&#41;</span>:
    <span style="color: #808080; font-style: italic;">#...</span></pre></td></tr></table></div>

<p>Si vous lisez <code>BaseAuthentificator</code>, vous n&#8217;avez pas besoin de voir qu&#8217;elle est parente d&#8217;autres classes plus bas pour savoir que ce n&#8217;est probablement pas une classe instanciable, mais sans doute une classe interface ou une classe abstraite. De quoi se faciliter une lecture en diagonale.</p>
<h2>FAIL</h2>
<p>Voici quelques exemples de noms qui ratent complètement l&#8217;objectif de documentation :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;">&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> do_query_database<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    <span style="color: #808080; font-style: italic;"># ...</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> query_database<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    <span style="color: #808080; font-style: italic;"># ...</span>
    do_query_database<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
    <span style="color: #808080; font-style: italic;"># ...</span></pre></td></tr></table></div>

<p>J&#8217;en croise dans le code source de Django, et ça me fait hurler. Sérieux ça veut dire quoi ? Qu&#8217;est-ce qui a été extrait ? Dans quel but ? On a plus de question APRÈS avoir lu le nom qu&#8217;avant, c&#8217;est encore pire qu&#8217;un mauvais nom, c&#8217;est un nom méchant.</p>
<p>Dans ce cas, il faut essayer d&#8217;expliquer au maximum ce que l&#8217;appendice &#8211; qui va me faire choper une péritonite &#8211; que vous avez mis de côté fait :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;">&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> excute_and_send_query<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    <span style="color: #808080; font-style: italic;"># ...</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> query_database<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    <span style="color: #808080; font-style: italic;"># ...</span>
    excute_and_send_query<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
    <span style="color: #808080; font-style: italic;"># ...</span></pre></td></tr></table></div>

<p>Un truc également exaspérant, c&#8217;est l&#8217;usage d&#8217;un vocabulaire ambigu :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">def</span> make_best_player_list<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    <span style="color: #808080; font-style: italic;"># ...</span></pre></td></tr></table></div>

<p>On sait ce que ça fait, ça fabrique une liste des meilleurs joueurs. Le contexte nous permet d&#8217;évaluer le résultat le plus probable. Maintenant un cas beaucoup moins clair :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">def</span> make_query<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    <span style="color: #808080; font-style: italic;"># ...</span></pre></td></tr></table></div>

<p>Ca envoie la requête, ça construit la requête ou les deux ? <code>Make</code> est un mot qui peut vouloir dire fabriquer ou exécuter. Ici il vaut mieux utiliser un vocabulaire plus explicite comme :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">def</span> build_sql_query<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    <span style="color: #808080; font-style: italic;"># ...</span></pre></td></tr></table></div>

<p>ou</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">def</span> send_db_query<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    <span style="color: #808080; font-style: italic;"># ...</span></pre></td></tr></table></div>

<p>Là on sait qui fait quoi. Quitte à faire :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">def</span> db_query<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    build_sql_query<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
    send_db_query<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>Et oui, diviser le travail en plusieurs sous unités bien nommées, puis les regrouper dans un bloc plus général est aussi une forme de documentation. Créer des fonctions n&#8217;est pas qu&#8217;une question de maintenance ou de perf. </p>
<p>Savoir bien nommer les choses vient avec de l’entraînement. Au début, il faut prendre le temps de le faire. Il faut s&#8217;arrêter, et se mettre à la place d&#8217;un autre dev qui n&#8217;a pas encore eu son café. </p>
<p>Allez, détendez-vous, ce blog est plein de code qui ne suit pas les conseils de cet article. Faites juste au mieux ok ?</p>


feed_id: http://sametmax.com/?p=12393
title: L&#8217;équation du nichon
uri: L-équation-du-nichon
url: http://sametmax.com/lequation-du-nichon/
content:
<p>Alors que je remontais l&#8217;Ecosse en stop avec un vieil ami, nous nous sommes faits ramasser par des Suisses. On a terminé dans un village au dessus d&#8217;Inverness. Un de nos hôtes, bien pinté, nous confie de but en blanc avec son accent de Genève qu&#8217;il aime quand les femmes lui roulent la bite.</p>
<p>Je sais, ce n&#8217;est pas facile à expliquer sans geste. Vous voyez les brulures indiennes ? C&#8217;est le même principe, mais à la verticale, et sur sa teub.</p>
<p>Enrichi de cette révélation, j&#8217;ai compris à quelle point la diversité des plaisirs était vaste. Ici, parlant de la queue d&#8217;un inconnu suisse dans le décor de flashback de Highlanders, et surtout de la prise en main qu&#8217;il préférait, et qui me paraissant, à moi, parfaitement désagréable.</p>
<p>Malgré cela, je continue d&#8217;être surpris par la variété de manières de toucher des nibars.</p>
<p>Ma maman (avec laquelle je parle beaucoup de cul, allez comprendre mon évolution psychique plus tard) m&#8217;avait toujours dis qu&#8217;il fallait y aller tout doucement.</p>
<p>Mais sur le terrain, le manuel de formation ne sert plus à rien. Il y a celles qui aiment qu&#8217;on les caresse. Celles qui aiment qu&#8217;on les suce. Celles qui aiment qui les mordille. Les morde. Les prenne en main. Les malaxe. Les tire. Les tord. Les pince. Les giffle. Ou qu&#8217;on leur souffle doucement dessus. </p>
<p>Une meuf m&#8217;a sorti une fois qu&#8217;elle demandait à un copain boulanger de lui bouler les seins, comme les miches de pain, et qu&#8217;elle adorait ça.</p>
<p>Il y a les sensibles, et celles qui ne voient pas l&#8217;interêt. Les fragiles, et les masos. Les amoureuses de têton, et les fans de la colerette.</p>
<p>Et toutes s&#8217;attendent à ce qu&#8217;on sache quoi faire parce que &#8220;c&#8217;est pas bien compliqué&#8221;.</p>
<p>Bref, ayant hier couché avec une meuf qui adore qu&#8217;on lui tire-bouchonne les tétés, la mémoire de la précédente qui avait mal dès qu&#8217;on posait la main dessus m&#8217;est revenu en mémoire.</p>
<p>L&#8217;équation du nichon a trop d&#8217;inconnues pour être résolue a priori. Il faut de la data pour pouvoir en faire quelque chose. De la collecte IRL, avec une mise à jour régulière.</p>
<p>Aussi, en ce jour, je poste cet article solidaire de tous les hommes qui, une fois qu&#8217;ils ont retiré le soutif, doivent se lancer dans une étude empirique pour savoir quoi faire avec ces nouvelles mamelles.</p>
<p>Petite astuce cependant, apprenez à retirer un  soutien-gorge d&#8217;une main, quitte à vous entrainer seul. Ca coûte rien, et c&#8217;est la classe.</p>


feed_id: http://sametmax.com/?p=12400
title: Pas Hexactement
uri: Pas-Hexactement
url: http://sametmax.com/pas-hexactement/
content:
<p>Je préfère utiliser le terme francophone que français pour le public du blog. D&#8217;ailleurs, quand je retweet des offres d&#8217;emploi, je le fais pour les pays limitrophes à la France, et également le Canada ou l&#8217;Afrique du Nord et de l&#8217;Ouest.</p>
<p>Ce n&#8217;est pas un hasard. En effet, si on regarde les stats du blog :</p>
<pre>France 	5,135
Belgium 	302
Canada 	130
Switzerland 	129
United States  States	105
Luxembourg 	64
Tunisia 	44
United Kingdom  Kingdom	40
Bulgaria 	39
New Caledonia	33
Algeria 	32
Réunion 	28
Morocco 	24</pre>
<p>302 + 130 + 129 + 64 + 32 + 24 = 681 vues qui viennent de pays francophones, soit plus de 10 %. Le français est beaucoup plus parlé dans le monde qu&#8217;on ne le croit. Sans parler des expats, évidement.</p>
<p>Donc à tout ceux qui ne sont pas de l&#8217;hexagone, coucou !</p>
<p>Je suis assez épaté du chiffre Bulgare ceci dit. </p>


feed_id: http://sametmax.com/?p=12406
title: Est-ce la fin de jQuery ?
uri: Est-ce-la-fin-de-jQuery
url: http://sametmax.com/est-ce-la-fin-de-jquery/
content:
<p>Avec un report massif des usagers sur des mobiles, la plupart sous un navigateur Webkit powered, on peut tabler sur un bien meilleur support de Javascript et ses APIs. Cela signifie qu&#8217;on a moins besoin d&#8217;utiliser des libs pour combler les trous, mais aussi la possibilité d&#8217;utiliser des frameworks comme AngularJS, MeteorJS, etc.</p>
<p>Est-ce pour autant la fin de notre bien aimé jQuery, qui nous a sorti de l&#8217;age sombre, et nous a tenu la main pendant cette dernière décénnie ?</p>
<p>Non.</p>
<p>Bien entendu, on utilise moins jQuery. On utilise parfois des choses plus légères. Parfois des choses plus lourdes. Parfois du JS pur. </p>
<p>Et il faut avouer que les projets parallèles à jQuery comme jQuery Mobile et jQueryUI n&#8217;ont jamais décollé. Merci Bootstrap et le responsive design.</p>
<p>Néanmoins, il reste des tas de choses pour lesquelles jQuery est utile.</p>
<p>Certes, il y a les versions light qui font &#8220;presque la même chose mais avec beaucoup moins de ko&#8221;. Mais c&#8217;est le &#8220;presque&#8221; qui finit par vous faire ajouter plein d&#8217;autres dépendances, pour finalement vous retrouver avec un truc qui fait &#8220;presque&#8221; la même taille que la lib que vous vouliez éviter, et qui ne sera probablement pas en cache. De plus, la documentation disponible n&#8217;est pas du tout comparable.</p>
<p>Et certes, il y a les outils bazooka, qui font tout, même le café. Mais les solutions comme Angular ne permettent pas une dégradation gracieuse du site, pèchent en référencement, et massacrent l&#8217;accessibilité. Les apps sont des bons candidats pour une &#8220;one page navigation&#8221;, mais pas les sites orientés contenus, quant aux hybrides&#8230;</p>
<p>Pensez aussi que même si vous codez pour des browsers modernes (donc pas IE8 qui limite ses sélecteurs à css 2.1), les APIs haut niveau comme <code>querySelector</code> et <code>querySelectorAll</code> sont très loin d&#8217;être aussi pratiques et puissantes que le bon vieux <code>$()</code>. Je ne parle même pas de la gestion des événements et d&#8217;Ajax qui sont toujours à chier en 2014.</p>
<p>Donc jQuery permet de rajouter cette petite touche de dynamisme à votre site statique, ou de faire un outil moderne sans sacrifier les aveugles et le PR. C&#8217;est un compromis entre puissance et simplicité. Et quand vous sortirez du cas standard, contrairement aux versions au bifidus actif allégé, la lib vous permettra de sauter le pas avec ses centaines de features, ou ses milliers de plugins.</p>
<p>Sans compter l&#8217;immense base de projets existants utilisant le bouzin, et qu&#8217;il va bien falloir maintenir. Bonne chance à ceux qui veulent porter un site avec jQuery vers un autre truc. N&#8217;oubliez pas non plus l&#8217;inertie technique. Et le temps de formation de la population de dev aux nouvelles technos. Surtout qu&#8217;en ce moment, avec l&#8217;avalanche de nouveaux trucs à tester/apprendre/valider, il va falloir gérer ses priorités. Ajoutez à ça la baisse drastique du niveau des devs sur le marché du travail :)</p>
<p>Bref, bien que j&#8217;apprécie et utilise les nombreuses alternatives à jQuery, il  ne va pas disparaitre cette année, et probablement pas l&#8217;année prochaine.</p>


feed_id: http://sametmax.com/?p=12424
title: Django pleure &#8216;MySQL server has gone away&#8217;
uri: Django-pleure-MySQL-server-has-gone-away
url: http://sametmax.com/django-pleure-mysql-server-has-gone-away/
content:
<p>Dans certaines circonstances, par exemple une transaction ouverte pendant trop longtemps, MySQL ferme la connexion avec son client. </p>
<p>Cela arrive par exemple quand on l&#8217;utilise comme broker pour celery. On a des tâches qui plantent, et quand on met du debug, on lit un <code>(2006, 'MySQL server has gone away')</code> bien cryptique.</p>
<p>Généralement je recommande de changer de backend ici. Passer à redis pour cet usage par exemple.</p>
<p>Mais parfois on ne peut pas. La solution est alors de forcer Django à réinitialiser la connexion en la fermant. Il faut le faire au niveau où on a remarqué que la requête échouait. Dans notre cas, au début de chaque tâche celery :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">from</span> django.<span style="color: black;">db</span> <span style="color: #ff7700;font-weight:bold;">import</span> connection 
&nbsp;
<span style="color: #66cc66;">@</span>task
<span style="color: #ff7700;font-weight:bold;">def</span> do_stuff<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    connection.<span style="color: black;">close</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
    <span style="color: #808080; font-style: italic;"># le reste du code</span></pre></td></tr></table></div>

<p>Voyant la connexion fermée, Django va en ouvrir une nouvelle à la prochaine requête automatiquement.</p>
<p>Cela a, évidement, un impact sur les performances, donc choisissez bien entre mettre une rustine et changer la roue.</p>


feed_id: http://sametmax.com/?p=12279
title: Redis : pourquoi et comment ?
uri: Redis-pourquoi-et-comment
url: http://sametmax.com/redis-pourquoi-et-comment/
content:
<p>Redis fait partie de ces technologies tellement utiles et simples à mettre en oeuvre qu&#8217;il est facile d&#8217;oublier toutes les personnes qui ne savent toujours pas ce que c&#8217;est. D&#8217;autant plus qu&#8217;on l&#8217;associe avec beaucoup d&#8217;étiquettes : cache, queues, pub/sub, base de données, nosql&#8230; Et qu&#8217;est-ce que Redis comparé à Memcache, MongoDB, MySQL, RabbitMQ, des technos qui n&#8217;ont rien à voir et auxquelles on le compare ?</p>
<p>Bref, c&#8217;est pas clair tout ça.</p>
<p><span class='embed-youtube' style='text-align:center; display: block;'><iframe class='youtube-player' type='text/html' width='1170' height='689' src='http://www.youtube.com/embed/6VAkOhXIsI0?version=3&#038;rel=1&#038;fs=1&#038;showsearch=0&#038;showinfo=1&#038;iv_load_policy=1&#038;wmode=transparent' frameborder='0' allowfullscreen='true'></iframe></span></p>
<h2>Hello redis</h2>
<h3>D&#8217;abord, installer le bouzin. </h3>
<p>Si vous êtes sous Linux, Redis est dans votre gestionnaire de paquets. Par exemple, sous Ubuntu :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #c20cb9; font-weight: bold;">sudo</span> <span style="color: #c20cb9; font-weight: bold;">apt-get install</span> redis-server</pre></td></tr></table></div>

<p>Pour Mac, via macport :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #c20cb9; font-weight: bold;">sudo</span> port <span style="color: #c20cb9; font-weight: bold;">install</span> redis
<span style="color: #c20cb9; font-weight: bold;">sudo</span> port load redis</pre></td></tr></table></div>

<p>Je crois que <code>brew install redis</code> marche aussi pour les amateurs de homebrew.</p>
<p>Pour Windows, il y a un exe à télécharger <a href="https://github.com/MSOpenTech/redis/blob/2.8/bin/release/redis-2.8.17.zip">ici</a>.</p>
<p>Mais le plus fun avec redis, c&#8217;est que même quand il y a pas de binaire, c&#8217;est le truc le plus facile du monde <a href="https://github.com/MSOpenTech/redis/blob/2.8/bin/release/redis-2.8.17.zip">à compiler.</a> Et Dieu sait que je hais la compilation, donc quand je vous dis que c&#8217;est simple, c&#8217;est que c&#8217;est mega, ultra, simple.</p>
<h3>Ensuite lui faire dire bonjour.</h3>
<p>Utiliser Redis se fait à base de commandes, dont <a href="http://redis.io/commands">la liste est sur le site officiel</a>. On peut envoyer ces commandes depuis n&#8217;importe quel langage, mais Redis fournit un shell qui permet de rentrer ces commandes directement:</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="bash" style="font-family:monospace;">$ redis-cli <span style="color: #666666; font-style: italic;"># lancer le shell redis</span>
127.0.0.1:<span style="color: #000000;">6379</span><span style="color: #000000; font-weight: bold;">&gt;</span>  ECHO <span style="color: #ff0000;">&quot;Hello&quot;</span>
<span style="color: #ff0000;">&quot;Hello&quot;</span></pre></td></tr></table></div>

<h2>Redis comme base de données clés/valeurs expirables</h2>
<p>L&#8217;usage de base de Redis, c&#8217;est de stocker des valeurs associées à des clés. Le serveur Redis est comme un gigantesque Hash Map, dictionnaire Python, object Javascript, Array associatif en PHP&#8230; En premier lieu, donc, on utilise Redis pour stocker des choses ainsi :</p>
<pre>"cle1" => valeur1
"cle2" => valeur2
etc</pre>
<p>La clé doit être une chaîne de caractères, de préférence ASCII. La valeur peut être n&#8217;importe quoi, vraiment, mais généralement c&#8217;est un gros bloc de texte, un entier ou un blob binaire.</p>
<p>Ca s&#8217;utilise avec les commandes <code>SET</code> et <code>GET</code>, qui peuvent, comme toutes les commandes, être tapées dans le shell de Redis :</p>
<pre>127.0.0.1:6379> GET une_cle
(nil)
127.0.0.1:6379> SET une_cle "Une valeur"
OK
127.0.0.1:6379> GET une_cle
"Une valeur"
127.0.0.1:6379> SET une_cle 780708
OK
127.0.0.1:6379> GET une_cle
"780708"</pre>
<p>Ce genre d&#8217;usage est surtout sollicité pour stocker des paramètres de configurations ou des compteurs.</p>
<p>En effet, la plupart des opérations sur les clés sont atomiques, rendant ce genre d&#8217;usage idéal. On peut même incrémenter ou décrémenter une valeur avec <code>INCR</code> et <code>DECR</code> atomiquement :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="bash" style="font-family:monospace;">127.0.0.1:<span style="color: #000000;">6379</span><span style="color: #000000; font-weight: bold;">&gt;</span> INCR une_cle
<span style="color: #7a0874; font-weight: bold;">&#40;</span>integer<span style="color: #7a0874; font-weight: bold;">&#41;</span> <span style="color: #000000;">780709</span>
127.0.0.1:<span style="color: #000000;">6379</span><span style="color: #000000; font-weight: bold;">&gt;</span> INCR une_cle
<span style="color: #7a0874; font-weight: bold;">&#40;</span>integer<span style="color: #7a0874; font-weight: bold;">&#41;</span> <span style="color: #000000;">780710</span>
127.0.0.1:<span style="color: #000000;">6379</span><span style="color: #000000; font-weight: bold;">&gt;</span> DECR une_cle
<span style="color: #7a0874; font-weight: bold;">&#40;</span>integer<span style="color: #7a0874; font-weight: bold;">&#41;</span> <span style="color: #000000;">780709</span>
127.0.0.1:<span style="color: #000000;">6379</span><span style="color: #000000; font-weight: bold;">&gt;</span></pre></td></tr></table></div>

<p>Vous allez me dire, mais quel intérêt ? Je peux déjà faire ça avec une variable. Certes, mais Redis est accessible depuis n&#8217;importe quel programme de votre serveur. Vous pouvez donc facilement partager des valeurs entre vos processus. Par exemple, avec Django, on a souvent plusieurs workers WSGI, et Redis permet donc de partager des informations entre ces workers. Pour cette raison, on peut utiliser Redis pour créer un <a href="https://github.com/antirez/redlock-rb">lock partagé</a>.</p>
<p>Ainsi, un paramètre dynamique peut être changé et lu depuis tous les process de votre projet en utilisant Redis, et la valeur sera garantie d&#8217;être à jour. On peut bien entendu faire ça avec une base de données ordinaire, mais Redis a un plus : la performance.</p>
<p>En effet, Redis est par défaut configuré pour garder toutes les données de sa base en mémoire vive. Pour cette raison, il est très, très rapide, supportant 100000 lectures/écritures par seconde. Si vous comptez le nombre de visiteurs en ligne pour l&#8217;afficher sur chaque page, votre base de données vous dira merci de plutôt demander à Redis.</p>
<p>Plus encore, les clés peuvent expirer :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="bash" style="font-family:monospace;">127.0.0.1:<span style="color: #000000;">6379</span><span style="color: #000000; font-weight: bold;">&gt;</span> SET une_autre_cle <span style="color: #ff0000;">&quot;Tu ne le sais pas mais tu es deja mort&quot;</span>
OK
127.0.0.1:<span style="color: #000000;">6379</span><span style="color: #000000; font-weight: bold;">&gt;</span> EXPIRE une_autre_cle <span style="color: #000000;">5</span> <span style="color: #666666; font-style: italic;"># cette clé expire dans 5 secondes</span>
<span style="color: #7a0874; font-weight: bold;">&#40;</span>integer<span style="color: #7a0874; font-weight: bold;">&#41;</span> <span style="color: #000000;">1</span>
127.0.0.1:<span style="color: #000000;">6379</span><span style="color: #000000; font-weight: bold;">&gt;</span> GET une_autre_cle
<span style="color: #ff0000;">&quot;Tu ne le sais pas mais tu es deja mort&quot;</span>
127.0.0.1:<span style="color: #000000;">6379</span><span style="color: #000000; font-weight: bold;">&gt;</span> GET une_autre_cle
<span style="color: #ff0000;">&quot;Tu ne le sais pas mais tu es deja mort&quot;</span>
127.0.0.1:<span style="color: #000000;">6379</span><span style="color: #000000; font-weight: bold;">&gt;</span> GET une_autre_cle
<span style="color: #ff0000;">&quot;Tu ne le sais pas mais tu es deja mort&quot;</span>
127.0.0.1:<span style="color: #000000;">6379</span><span style="color: #000000; font-weight: bold;">&gt;</span> GET une_autre_cle
<span style="color: #7a0874; font-weight: bold;">&#40;</span>nil<span style="color: #7a0874; font-weight: bold;">&#41;</span>
127.0.0.1:<span style="color: #000000;">6379</span><span style="color: #000000; font-weight: bold;">&gt;</span> GET une_autre_cle
<span style="color: #7a0874; font-weight: bold;">&#40;</span>nil<span style="color: #7a0874; font-weight: bold;">&#41;</span></pre></td></tr></table></div>

<p>La limite en taille de ce qu&#8217;on peut stocker par couple est <a href="http://sametmax.com/les-limites-théoriques-de-redis/">assez large</a>.</p>
<p>On peut également utiliser <code>EXPIREAT</code> et un timestamp unique si on a une date en tête.</p>
<p>Cette caractéristique le rend similaire à Memcache, qui est basé sur des clés/valeurs en mémoire qui peuvent expirer. Et comme Memcache, cela fait de Redis un outil idéal pour gérer du cache : faites une opération longue, stockez-là avec une clé, mettez lui une date d&#8217;expiration et pouf, vous avez une valeur cachée globale à votre app.</p>
<p>Redis a néanmoins 3 différences majeures qui le sépare de Memcache :</p>
<ul>
<li>Redis sauvegarde régulièrement toutes les données sur le disque. Si vous rebootez le serveur, vous perdez au pire, quelques secondes de données. Avec Memcache, vous perdez tout.</li>
<li>Memcache possède des fonctionalités de clusterisation que n&#8217;a pas encore Redis, bien que ce soit actuellement en beta.</li>
<li>Redis peut faire bien plus que du stockage clé/valeur.</li>
</ul>
<h2>Redis comme base NoSQL zarbie</h2>
<p>Redis n&#8217;a pas besoin d&#8217;un schéma particulier à définir pour pouvoir sauvegarder ses données, mais n&#8217;est pas pour autant limité à une forme d&#8217;organisation basique. En fait, des types très proches de ceux qu&#8217;on trouve dans le langage Python sont disponibles pour stocker internalement les données, et ils sont <a href="http://redis.io/topics/data-types-intro">décrits dans son excellente doc</a>.</p>
<h3>Liste</h3>
<p>Une <a href="http://redis.io/commands#list">liste</a> est juste une collection ordonnée d&#8217;éléments. On utilise toujours la logique de clé, mais au lieu d&#8217;une valeur, on a une séquence d&#8217;éléments.</p>
<p>Cela permet d&#8217;avoir :</p>
<pre>cle => [
	valeur1,
	valeur2,
	...
]</pre>
<p>Dans le shell :</p>
<pre>127.0.0.1:6379> lpush batman na
(integer) 1
127.0.0.1:6379> lpush batman na
(integer) 2
127.0.0.1:6379> lpush batman na
(integer) 3
127.0.0.1:6379> lpush batman na
(integer) 4
127.0.0.1:6379> lpush batman na
(integer) 5
127.0.0.1:6379> lpush batman na
(integer) 6
127.0.0.1:6379> llen batman
(integer) 6
127.0.0.1:6379> LINDEX batman 3
"na"
127.0.0.1:6379> LINDEX batman 10
(nil)
127.0.0.1:6379> LRANGE batman 0 -1 # du début au dernier élément
1) "na"
2) "na"
3) "na"
4) "na"
5) "na"
6) "na"
127.0.0.1:6379> LRANGE batman 2 3
1) "na"
2) "na"
127.0.0.1:6379></pre>
<p>On peut faire toutes les opérations qu&#8217;on a l&#8217;habitude de faire sur des listes : récupérer un élément, en ajouter un, en retirer un, faire du LIFO, du FIFO, du pipo, etc.</p>
<p>Utile pour créer des files d&#8217;attente, des journaux d&#8217;évènements (pensez jeux vidéos) ou plus simplement une valeur de config plus complexe qu&#8217;une entrée.</p>
<h3>Hash</h3>
<p><a href="http://redis.io/commands#hash">Le Hash</a> se comporte comme un Hash Map, dictionnaire Python, object Javascript, Array associatif en PHP&#8230; Bref, comme Redis lui-même en fait, mais sans expiration de clé. Cela permet d&#8217;avoir :</p>
<pre>cle => {
	cle : valeur,
	cle : valeur,
}</pre>
<p>Dans le shell :</p>
<pre>127.0.0.1:6379> HSET scores titi 1
(integer) 1
127.0.0.1:6379> HSET scores grosminet 0
(integer) 1
127.0.0.1:6379> HSET scores tom 0
(integer) 1
127.0.0.1:6379> HSET scores jerry 1
(integer) 1
127.0.0.1:6379> HGET scores jerry
"1"
127.0.0.1:6379> HGETALL scores
1) "titi"
2) "1"
3) "grosminet"
4) "0"
5) "tom"
6) "0"
7) "jerry"
8) "1"
127.0.0.1:6379></pre>
<p>Notez encore une fois qu&#8217;il n&#8217;est pas utile de vérifier que la clé existe avant de rajouter une valeur dans le hash, bien qu&#8217;il y ait une commande pour le faire. Si on essaye de récupérer une clé qui n&#8217;existe pas, Redis retourne <code>nil</code>.</p>
<p>Le hash est fort pratique pour toute forme de compteurs groupés, ou juste pour mettre en cache des relations. Redis n&#8217;ayant pas de <code>JOIN</code>, on utilise parfois un hash pour faire le lien entre deux listes par exemple.</p>
<h3>Set</h3>
<p>Comme les sets en Python, le <a href="http://redis.io/commands#set">set</a> est une collection NON ordonnée d&#8217;éléments uniques. Il ne peut pas y avoir de doublons dans un set, et vérifier si un élément fait partie d&#8217;un set est une opération très rapide. Ils permettent aussi de faire des opérations ensemblistes de manière performante, par exemple vérifier quels éléments d&#8217;un set sont ou non dans un autre set.</p>
<pre>cle => { valeur1, valeur2, ...}</pre>
<p>Dans le shell :</p>
<pre>127.0.0.1:6379> SADD ip 192.168.1.1
(integer) 1
127.0.0.1:6379> SADD ip 192.168.1.1 # ajouter 2x le même ne fait rien
(integer) 0
127.0.0.1:6379> SADD ip 192.168.1.1
(integer) 0
127.0.0.1:6379> SADD ip 192.168.1.2
(integer) 1
127.0.0.1:6379> SADD ip 192.168.1.3
(integer) 1
127.0.0.1:6379> SCARD ip
(integer) 3
127.0.0.1:6379> SMEMBERS ip
1) "192.168.1.2"
2) "192.168.1.1"
3) "192.168.1.3"
127.0.0.1:6379> SADD ip:banned 192.168.1.3 # le ":" est une séparateur courant pour les clés
(integer) 1
127.0.0.1:6379> SADD ip:banned 192.168.1.10 # ip:banned est un AUTRE set
(integer) 1
127.0.0.1:6379> SINTER ip ip:banned # trouver les IP qui sont dans les 2 sets
1) "192.168.1.3"</pre>
<p>On va utiliser les sets pour éviter les doublons (tirage au sort par exemple) ou pour vérifier facilement une appartenance (notion de groupes, de permissions, etc.).</p>
<p>Le set possède une variante, le <a href="http://redis.io/commands#sorted_set">set ordonné</a>, qui associe à chaque élément du set un score. On peut changer ce score, l&#8217;incrémenter ou le décrémenter atomiquement, avoir deux scores égaux&#8230; Et au final, récupérer le set dans l&#8217;ordre ascendant ou descendant des scores. </p>
<pre>cle => { valeur1 (1), valeur2 (3), ...}</pre>
<p>Dans le shell :</p>
<pre>127.0.0.1:6379> zadd participants 1 staline
(integer) 1
127.0.0.1:6379> zadd participants 1 hitler
(integer) 1
127.0.0.1:6379> zadd participants 2 "pol pot"
(integer) 1
127.0.0.1:6379> zadd participants 1999 "rainbow dash"
(integer) 1
127.0.0.1:6379> zrange participants 0 - 1
(error) ERR value is not an integer or out of range
127.0.0.1:6379> zrange participants 0 -1 
1) "hitler"
2) "staline"
3) "pol pot"
4) "rainbow dash"
127.0.0.1:6379> zrange participants 0 -1 withscores
1) "hitler"
2) "1"
3) "staline"
4) "1"
5) "pol pot"
6) "2"
7) "rainbow dash"
8) "1999"
</pre>
<h3>HyperLogLog</h3>
<p>J&#8217;ai déjà parlé de l&#8217;HyperLogLog <a href="http://sametmax.com/le-compteur-mal-connu-lhyperloglog/">ici</a> et <a href="http://redis.io/commands#hyperloglog">celui de Redis</a> fonctionne pareil. Cette structure de données permettra de faire des compteurs d&#8217;éléments uniques, comme par exemple un compteur de visiteurs ou de gens connectés, qui soit approximatif (+ ou &#8211; 1%) mais prenne une taille fixe en mémoire.</p>
<p>Dans le shell :</p>
<pre>127.0.0.1:6379> PFADD connectes toto
(integer) 1
127.0.0.1:6379> PFADD connectes toto
(integer) 0
127.0.0.1:6379> PFADD connectes toto
(integer) 0
127.0.0.1:6379> PFADD connectes tata
(integer) 1
127.0.0.1:6379> PFADD connectes titi
(integer) 1
127.0.0.1:6379> PFADD connectes tutu
(integer) 1
127.0.0.1:6379> PFADD connectes tutu
(integer) 0
127.0.0.1:6379> PFADD connectes tutu
(integer) 0
127.0.0.1:6379> PFADD connectes tete
(integer) 1
127.0.0.1:6379> PFADD connectes bob
(integer) 1
127.0.0.1:6379> PFcount connectes
(integer) 6
127.0.0.1:6379>
</pre>
<h2>Redis comme super pote de Python</h2>
<p>Vu que Redis est simple à installer et à configurer, c&#8217;est un outil qu&#8217;on dégaine facilement, même pour un petit script, pas forcément pour une grosse app Web. Par exemple, je fais une analyse de mon serveur, plutôt que de stocker le résultat dans un fichier, je peux mettre tout ça dans Redis, c&#8217;est tellement pratique.</p>
<p>D&#8217;abord, la <a href="https://pypi.python.org/pypi/redis/">lib</a> pour communiquer avec Redis est à un <a href="http://sametmax.com/votre-python-aime-les-pip/">pip</a> du clavier :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="bash" style="font-family:monospace;">pip <span style="color: #c20cb9; font-weight: bold;">install</span> redis</pre></td></tr></table></div>

<p>Ensuite, si vous utilisez le client <code>StrictRedis</code>, l&#8217;API est exactement la même que les commandes du shell :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #ff7700;font-weight:bold;">import</span> redis
<span style="color: #66cc66;">&gt;&gt;&gt;</span> r <span style="color: #66cc66;">=</span> redis.<span style="color: black;">StrictRedis</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> r.<span style="color: black;">hgetall</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'scores'</span><span style="color: black;">&#41;</span>
<span style="color: black;">&#123;</span>b<span style="color: #483d8b;">'titi'</span>: b<span style="color: #483d8b;">'1'</span><span style="color: #66cc66;">,</span> b<span style="color: #483d8b;">'tom'</span>: b<span style="color: #483d8b;">'0'</span><span style="color: #66cc66;">,</span> b<span style="color: #483d8b;">'jerry'</span>: b<span style="color: #483d8b;">'1'</span><span style="color: #66cc66;">,</span> b<span style="color: #483d8b;">'grosminet'</span>: b<span style="color: #483d8b;">'0'</span><span style="color: black;">&#125;</span></pre></td></tr></table></div>

<p>Il existe aussi des drivers asynchrones pour tornado, twisted et asyncio.</p>
<h2>Redis comme message broker</h2>
<p>J&#8217;aime le <a href="http://redis.io/commands#pubsub">pub/sub</a>, je pense qu&#8217;après mon <a href="http://sametmax.com/introduction-a-wamp-en-python/">enthousiasme</a> pour WAMP.ws, c&#8217;est clair.</p>
<p>Redis met à disposition des primitives pour créer des files d&#8217;attente de messages et les lire, comme une version simplifiée de RabbitMQ ou Crossbar.io. Pour que ce soit intéressant, il nous faut deux process. D&#8217;abord un shell Python qui écoute les messages arrivant sur la file &#8220;sametmax&#8221; :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #ff7700;font-weight:bold;">import</span> redis
<span style="color: #66cc66;">&gt;&gt;&gt;</span> r <span style="color: #66cc66;">=</span> redis.<span style="color: black;">StrictRedis</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> listener <span style="color: #66cc66;">=</span> r.<span style="color: black;">pubsub</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> listener.<span style="color: black;">subscribe</span><span style="color: black;">&#40;</span><span style="color: black;">&#91;</span><span style="color: #483d8b;">'sametmax'</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #ff7700;font-weight:bold;">for</span> item <span style="color: #ff7700;font-weight:bold;">in</span> listener.<span style="color: black;">listen</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
...     <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span>item<span style="color: black;">&#41;</span>
...</pre></td></tr></table></div>

<p>Le code va bloquer, et affichera quelque chose à chaque fois qu&#8217;il reçoit un message.</p>
<p>Du coup si je fais ceci dans le shell Redis :</p>
<pre>127.0.0.1:6379> publish sametmax yolo
(integer) 1
127.0.0.1:6379> publish sametmax carpediem
(integer) 1
127.0.0.1:6379> publish sametmax wololo
(integer) 1
127.0.0.1:6379> publish sametmax2 oyooyo
(integer) 0
127.0.0.1:6379></pre>
<p>Mon shell python va afficher :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: black;">&#123;</span><span style="color: #483d8b;">'type'</span>: <span style="color: #483d8b;">'subscribe'</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'pattern'</span>: <span style="color: #008000;">None</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'channel'</span>: b<span style="color: #483d8b;">'sametmax'</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'data'</span>: <span style="color: #ff4500;">1</span><span style="color: black;">&#125;</span>
<span style="color: black;">&#123;</span><span style="color: #483d8b;">'type'</span>: <span style="color: #483d8b;">'message'</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'pattern'</span>: <span style="color: #008000;">None</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'channel'</span>: b<span style="color: #483d8b;">'sametmax'</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'data'</span>: b<span style="color: #483d8b;">'yolo'</span><span style="color: black;">&#125;</span>
<span style="color: black;">&#123;</span><span style="color: #483d8b;">'type'</span>: <span style="color: #483d8b;">'message'</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'pattern'</span>: <span style="color: #008000;">None</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'channel'</span>: b<span style="color: #483d8b;">'sametmax'</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'data'</span>: b<span style="color: #483d8b;">'carpediem'</span><span style="color: black;">&#125;</span>
<span style="color: black;">&#123;</span><span style="color: #483d8b;">'type'</span>: <span style="color: #483d8b;">'message'</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'pattern'</span>: <span style="color: #008000;">None</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'channel'</span>: b<span style="color: #483d8b;">'sametmax'</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'data'</span>: b<span style="color: #483d8b;">'wololo'</span><span style="color: black;">&#125;</span></pre></td></tr></table></div>

<p>Il n&#8217;a pas affiché <code>oyooyo</code> puisque c&#8217;est sur une autre channel.</p>
<p>C&#8217;est une méthode assez simple de faire du pub/sub. C&#8217;est bas niveau, il n&#8217;y a pas de RPC, il faut boucler à la main et créer soit-même la mécanique pour arrêter d&#8217;écouter ou faire du multitask, mais c&#8217;est facile pour débuter. Pour cette raison, plein de gens utilisent une solution bricolée là-dessus pour faire du pub/sub.</p>
<h2>Et donc</h2>
<p>Non seulement Redis est facile à installer, simple à utiliser et performant, mais en plus il est accessible depuis de nombreux langages. Ajoutez à cela ses très nombreuses fonctionnalités, et vous avez là un système qui est installé par défaut sur la plupart de mes serveurs. Par ailleurs, suivez <a href="http://antirez.com/latest/0">le blog de l&#8217;auteur</a>, ce mec est un génie. Il écrit pas souvent, mais quand il écrit, c&#8217;est passionant, et humble. C&#8217;est beau.</p>


feed_id: http://sametmax.com/?p=12456
title: Appliquer un traitement à tous les fichiers d&#8217;un dossier en Python
uri: Appliquer-un-traitement-à-tous-les-fichiers-d-un-dossier-en-Python
url: http://sametmax.com/appliquer-un-traitement-a-tous-les-fichiers-dun-dossier-en-python/
content:
<p>Opération courante en informatique et on a tous eu besoin de chercher comment faire une fois.</p>
<p>Soit l’arborescence :</p>
<pre>test
├── dossier
│   ├── fichier.py
│   ├── fichier.txt
│   └── pas_un_dossier.txt
├── Dossier
│   ├── dOssier
│   │   └── faichier
│   └── fichiiiiiiiiier
├── .fichier
├── fichier
├── fIchier
└── Fichier
</pre>
<h2>Lister le contenu d&#8217;un dossier</h2>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">os</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #dc143c;">os</span>.<span style="color: black;">listdir</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'.'</span><span style="color: black;">&#41;</span>
<span style="color: black;">&#91;</span><span style="color: #483d8b;">'dossier'</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'Dossier'</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'fichier'</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'fIchier'</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'.fichier'</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'Fichier'</span><span style="color: black;">&#93;</span></pre></td></tr></table></div>

<p>On récupère les noms des dossiers et les fichiers, y compris cachés, mais pas les dossiers spéciaux types <code>..</code> et <code>.</code>.</p>
<p>Le type des noms retournés est <code>str</code> que ce soit en Python 2 ou 3. Ça a l&#8217;air cool et homogène comme ça, jusqu&#8217;à ce qu&#8217;on se souvienne que <code>str</code> sont des bits en Python 2 et de l&#8217;unicode en Python 3. Donc gaffe quand vous portez votre code d&#8217;une version à l&#8217;autre. Les noms de fichiers contiennent des caractères non ASCII dans la vraie vie vivante.</p>
<p>Si vous voulez récupérer uniquement les dossiers ou les fichiers, il va falloir filtrer :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #ff7700;font-weight:bold;">for</span> element <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #dc143c;">os</span>.<span style="color: black;">listdir</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'/tmp/test'</span><span style="color: black;">&#41;</span>:
...     <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #dc143c;">os</span>.<span style="color: black;">path</span>.<span style="color: black;">isdir</span><span style="color: black;">&#40;</span>element<span style="color: black;">&#41;</span>:
...         <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;'%s' un dossier&quot;</span> % element<span style="color: black;">&#41;</span>
...     <span style="color: #ff7700;font-weight:bold;">else</span>:
...         <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;'%s' est un fichier&quot;</span> % element<span style="color: black;">&#41;</span>
<span style="color: #483d8b;">'dossier'</span> un dossier
<span style="color: #483d8b;">'Dossier'</span> un dossier
<span style="color: #483d8b;">'fichier'</span> est un fichier
<span style="color: #483d8b;">'fIchier'</span> est un fichier
<span style="color: #483d8b;">'.fichier'</span> est un fichier
<span style="color: #483d8b;">'Fichier'</span> est un fichier</pre></td></tr></table></div>

<p>Pareil si on veut filtrer par extensions :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #ff7700;font-weight:bold;">for</span> element <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #dc143c;">os</span>.<span style="color: black;">listdir</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'/tmp/test/dossier'</span><span style="color: black;">&#41;</span>:
...     <span style="color: #ff7700;font-weight:bold;">if</span> element.<span style="color: black;">endswith</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'.txt'</span><span style="color: black;">&#41;</span>:
...         <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;'%s' est un fichier texte&quot;</span> % element<span style="color: black;">&#41;</span>
...     <span style="color: #ff7700;font-weight:bold;">else</span>:
...         <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;'%s' n'est pas un fichier texte&quot;</span> % element<span style="color: black;">&#41;</span>
<span style="color: #483d8b;">'fichier.txt'</span> est un fichier texte
<span style="color: #483d8b;">'pas_un_dossier.txt'</span> est un fichier texte
<span style="color: #483d8b;">'fichier.py'</span> n<span style="color: #483d8b;">'est pas un fichier texte</span></pre></td></tr></table></div>

<p>Néanmoins, Python vient avec le module <code>glob</code> qui permet de demander le listing du contenu d&#8217;un dossier en appliquant des filtres Unix :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">glob</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #dc143c;">glob</span>.<span style="color: #dc143c;">glob</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'/tmp/test/dossier/*.txt'</span><span style="color: black;">&#41;</span>
<span style="color: black;">&#91;</span><span style="color: #483d8b;">'/tmp/test/dossier/fichier.txt'</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'/tmp/test/dossier/pas_un_dossier.txt'</span><span style="color: black;">&#93;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #dc143c;">glob</span>.<span style="color: #dc143c;">glob</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'./dossier/*.txt'</span><span style="color: black;">&#41;</span>
<span style="color: black;">&#91;</span><span style="color: #483d8b;">'./dossier/fichier.txt'</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'./dossier/pas_un_dossier.txt'</span><span style="color: black;">&#93;</span></pre></td></tr></table></div>

<p>Mais comme vous pouvez le voir, le comportement n&#8217;est pas le même que <code>listdir</code> : les éléments de la liste sont des chemins relatifs à celui passé en paramètre si il est lui-même relatif, ou absolus si celui passé en paramètre est absolu. N&#8217;oubliez donc pas de normaliser l&#8217;entrée ou la sortie avec <code>os.path.realpath</code> qui retournera un chemin canonique.</p>
<p>Même problème Python 2/3 : le type est <code>str</code> dans les 2 cas. </p>
<h2>Parcours récursif</h2>
<p>La fonction <code>os.walk</code> permet de lister récursivement tous les fichiers et les dossiers à partir d&#8217;un point dans l&#8217;arborescence. C&#8217;est un générateur, et sa valeur de retour est un peu particulière et se récupère via <a href="http://sametmax.com/tag/unpacking/">unpacking</a>:</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">for</span> dossier<span style="color: #66cc66;">,</span> sous_dossiers<span style="color: #66cc66;">,</span> fichiers <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #dc143c;">os</span>.<span style="color: black;">walk</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'/tmp/test'</span><span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'##### %s #####'</span> % dossier<span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;Sous dossiers : %s&quot;</span> % sous_dossiers<span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;Fichiers : %s&quot;</span> % fichiers<span style="color: black;">&#41;</span>
<span style="color: #808080; font-style: italic;">##### /tmp/test #####</span>
Sous dossiers : <span style="color: black;">&#91;</span><span style="color: #483d8b;">'dossier'</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'Dossier'</span><span style="color: black;">&#93;</span>
Fichiers : <span style="color: black;">&#91;</span><span style="color: #483d8b;">'fichier'</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'fIchier'</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'.fichier'</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'Fichier'</span><span style="color: black;">&#93;</span>
<span style="color: #808080; font-style: italic;">##### /tmp/test/dossier #####</span>
Sous dossiers : <span style="color: black;">&#91;</span><span style="color: black;">&#93;</span>
Fichiers : <span style="color: black;">&#91;</span><span style="color: #483d8b;">'fichier.txt'</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'pas_un_dossier.txt'</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'fichier.py'</span><span style="color: black;">&#93;</span>
<span style="color: #808080; font-style: italic;">##### /tmp/test/Dossier #####</span>
Sous dossiers : <span style="color: black;">&#91;</span><span style="color: #483d8b;">'dOssier'</span><span style="color: black;">&#93;</span>
Fichiers : <span style="color: black;">&#91;</span><span style="color: #483d8b;">'fichiiiiiiiiier'</span><span style="color: black;">&#93;</span>
<span style="color: #808080; font-style: italic;">##### /tmp/test/Dossier/dOssier #####</span>
Sous dossiers : <span style="color: black;">&#91;</span><span style="color: black;">&#93;</span>
Fichiers : <span style="color: black;">&#91;</span><span style="color: #483d8b;">'faichier'</span><span style="color: black;">&#93;</span></pre></td></tr></table></div>

<p>Du coup, si vous voulez avoir la liste des chemin des fichiers absolus, il faut reconstituer à la main :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">for</span> dossier<span style="color: #66cc66;">,</span> sous_dossiers<span style="color: #66cc66;">,</span> fichiers <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #dc143c;">os</span>.<span style="color: black;">walk</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'/tmp/test'</span><span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">for</span> fichier <span style="color: #ff7700;font-weight:bold;">in</span> fichiers:
        <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span><span style="color: #dc143c;">os</span>.<span style="color: black;">path</span>.<span style="color: black;">join</span><span style="color: black;">&#40;</span>dossier<span style="color: #66cc66;">,</span> fichier<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
/tmp/<span style="color: #dc143c;">test</span>/fichier
/tmp/<span style="color: #dc143c;">test</span>/fIchier
/tmp/<span style="color: #dc143c;">test</span>/.<span style="color: black;">fichier</span>
/tmp/<span style="color: #dc143c;">test</span>/Fichier
/tmp/<span style="color: #dc143c;">test</span>/dossier/fichier.<span style="color: black;">txt</span>
/tmp/<span style="color: #dc143c;">test</span>/dossier/pas_un_dossier.<span style="color: black;">txt</span>
/tmp/<span style="color: #dc143c;">test</span>/dossier/fichier.<span style="color: black;">py</span>
/tmp/<span style="color: #dc143c;">test</span>/Dossier/fichiiiiiiiiier
/tmp/<span style="color: #dc143c;">test</span>/Dossier/dOssier/faichier</pre></td></tr></table></div>

<p>Encore une fois, c&#8217;est du <code>str</code> partout, alors attention. L&#8217;article sur l&#8217;<a href="http://sametmax.com/lencoding-en-python-une-bonne-fois-pour-toute/">encoding en Python </a>reste un des plus consultés de la categ prog.</p>
<h2>Avec une lib qui va bien</h2>
<p>Je n&#8217;ai jamais caché mon amour immodéré pour <a href="https://pythonhosted.org/path.py/api.html">path.py</a> (qui enterre tous ses concurrents, dont unipath), qui encapsule toutes les opérations des fichiers de manière simple et élégante et qui marche sous Python 2 et 3.</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="bash" style="font-family:monospace;">pip <span style="color: #c20cb9; font-weight: bold;">install</span> path.py</pre></td></tr></table></div>

<p>Et c&#8217;est quand même plus facile pour le parcours récursif :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #ff7700;font-weight:bold;">from</span> path <span style="color: #ff7700;font-weight:bold;">import</span> path
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #ff7700;font-weight:bold;">for</span> f <span style="color: #ff7700;font-weight:bold;">in</span> path<span style="color: black;">&#40;</span><span style="color: #483d8b;">'.'</span><span style="color: black;">&#41;</span>.<span style="color: black;">walkfiles</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">print</span> f
   ....:     
./dossier/fichier.<span style="color: black;">txt</span>
./dossier/pas_un_dossier.<span style="color: black;">txt</span>
./dossier/fichier.<span style="color: black;">py</span>
./Dossier/fichiiiiiiiiier
./Dossier/dOssier/faichier
./fichier
./fIchier
./.<span style="color: black;">fichier</span>
./Fichier</pre></td></tr></table></div>

<p>En plus, <code>f</code> est de type <code>path</code> sous Python 2 et 3. C&#8217;est homogène, et ça permet de faire toutes les opérations magiques que ce type permet.</p>
<p>Néanmoins, si vous êtes sous Python 3.4 et que vous ne voulez pas ajouter une dépendance externe, vous pouvez utiliser le module <a href="https://docs.python.org/3/library/pathlib.html">pathlib</a> :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #ff7700;font-weight:bold;">from</span> pathlib <span style="color: #ff7700;font-weight:bold;">import</span> Path
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #ff7700;font-weight:bold;">for</span> p <span style="color: #ff7700;font-weight:bold;">in</span>  Path<span style="color: black;">&#40;</span><span style="color: #483d8b;">'.'</span><span style="color: black;">&#41;</span>.<span style="color: #dc143c;">glob</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'./**/*'</span><span style="color: black;">&#41;</span>:
...    <span style="color: #ff7700;font-weight:bold;">if</span> p.<span style="color: black;">is_file</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
...        <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span>p<span style="color: black;">&#41;</span>
fichier
fIchier
.<span style="color: black;">fichier</span>
Fichier
dossier/fichier.<span style="color: black;">txt</span>
dossier/pas_un_dossier.<span style="color: black;">txt</span>
dossier/fichier.<span style="color: black;">py</span>
Dossier/fichiiiiiiiiier
Dossier/dOssier/faichier</pre></td></tr></table></div>


feed_id: http://sametmax.com/?p=12464
title: Ceci n&#8217;est pas une pipe
uri: Ceci-n-est-pas-une-pipe
url: http://sametmax.com/ceci-nest-pas-une-pipe/
content:
<p>Ni un forum. Ni un chan IRC. C&#8217;est un blog.</p>
<p>Pour cette raison, il est inutile de demander de l&#8217;aide en commentaire. Faites-le dans un endroit qui est adapté pour cela.</p>
<p>Exemple, pour Python :</p>
<ul>
<li><a href="http://www.afpy.org/forums/forum_python">Forum de l&#8217;afpy</a></li>
<li><a href="http://www.developpez.net/forums/f96/autres-langages/python-zope/">Forum de developpez.com</a></li>
<li><a href="http://fr.openclassrooms.com/forum/categorie/langage-python">Forum d&#8217;openclassroom</a></li>
<li><a href="http://forum.hardware.fr/hfr/Programmation/Python/liste_sujet-1.htm">Forum de hardware.fr</a></li>
<li>News group Python fr : news:fr.comp.lang.python </li>
</ul>
<p>Un commentaire se doit d&#8217;être en lien avec l&#8217;article posé, ou un autre commentaire. La seule exception est pour les anciens du blog, qui ont carte blanche car ils ont participé à la création de la communauté, et c&#8217;est un peu chez eux.</p>
<p>Abordons maintenant le point délicat du formulaire de contact. Il peut servir à poser des questions qui ne sont pas liées à un article, pourvu que :</p>
<ul>
<li>Ce ne soit pas un débat.</li>
<li>Ce ne soit pas une demande de dépannage.</li>
</ul>
<p>Si vous ne le faites pas et que je suis de mauvais poil, la réponse risque de ne pas être celle attendue. Pour vous donner un exemple, voici cet article tel que je l&#8217;aurais écrit un jour grincheux :</p>
<blockquote><p>Ceci n&#8217;est pas une pipe</p>
<p>Ni un forum. Ni un chan IRC. C&#8217;est un blog.</p>
<p>Si vous avez une question posez la plutôt sur un forum d&#8217;entre-aide, vous aurez une chance d&#8217;avoir une réponse, et vous nous éviterez de vous ajouter à la liste des milliers de personnes qui nous ont fait perdre du temps avant vous.</p>
<p>Car oui vous êtes le 9878eme, non, on ne vous doit rien, et enfin, ce blog demande des centaines d&#8217;heures de travail par mois. Bref, on a pas que ça à foutre de vous modérer parce que vous n&#8217;avez pas eu la politesse de vous sortir les doigts du cul pour faire une recherche sur google et trouver un endroit qui est FAIT pour poser des questions.</p>
<p>Exemple, pour Python :</p>
<p>http://www.afpy.org/forums/forum_python&#8221;>Forum de l&#8217;afpy<br />
http://www.developpez.net/forums/f96/autres-langages/python-zope/&#8221;>Forum de devloppez.com<br />
http://fr.openclassrooms.com/forum/categorie/langage-python&#8221;>Forum d&#8217;openclassroom<br />
http://forum.hardware.fr/hfr/Programmation/Python/liste_sujet-1.htm&#8221;>Forum de hardware.fr</p>
<p>Oua, ça m&#8217;a pris 10 minutes pour trouver ces liens, et ce n&#8217;est QUE la partie fr.</p>
<p>Si vous n&#8217;êtes pas foutu de bouger votre fion pour trouver ces endroits, sérieusement, pourquoi voudriez-vous que je frémisse le petit doigt pour votre tronche de feignasse ?</p>
<p>Et si vous vous demandez pourquoi le ton de l&#8217;article est agressif, c&#8217;est parce que la masse de connards passifs me casse les couilles, et que si j&#8217;ai posté le lien, vous en faites partie.
</p></blockquote>
<p>Vous comprenez donc qu&#8217;il est préférable de garder cet espace joyeux, libre de haine et plein d&#8217;arc-en-ciels dans le cœur.</p>
<p>Sauvez un chaton, écrivez vos demandes d&#8217;aide sur un forum.</p>


feed_id: http://sametmax.com/?p=12476
title: Comment écrire une annonce pour recruter des dev
uri: Comment-écrire-une-annonce-pour-recruter-des-dev
url: http://sametmax.com/comment-ecrire-une-annonce-pour-recruter-des-dev/
content:
<p>Je critique souvent les offres d&#8217;emploi, mais l&#8217;art est difficile, alors voici quelques lignes directrices si cela vous arrive un jour.</p>
<h2>Ne mettez pas les RH en avant</h2>
<p>Les RH ne doivent PAS rédiger l&#8217;annonce. Le moyen de contact ne doit PAS être celui des RH.</p>
<p>Je ne dis pas que les RH ne doivent pas faire partie du processus de recrutement. Mais je recommande qu&#8217;ils s&#8217;en tiennent à l&#8217;administratif et à l&#8217;accompagnement de l&#8217;équipe technique dans la démarche.</p>
<p>Ils ne sont tout simplement pas qualifiés pour ça.</p>
<p>Ce n&#8217;est pas une insulte, c&#8217;est un constat que je fais tous les jours. Ils ne sont pas capables d&#8217;évaluer un profil technique correctement. Ils recalent trop facilement de bons profils pour délit de sale gueule (courant en info). Ils ne savent pas lire un CV tech, ils vont juste comparer les besoins de l&#8217;annonce avec le papier.</p>
<p>Mettez les membres de l&#8217;équipe qui va accueillir la recrue comme contact, et demandez leur de rédiger l&#8217;annonce.</p>
<p>Cela a de nombreux avantages :</p>
<ul>
<li>Ils se sentent valorisés.</li>
<li>Ils sont impliqués dans le choix de leur collègue, l&#8217;intégration sera meilleure.</li>
<li>Ils peuvent voir des choses lors de l&#8217;entretien ou sur un CV qui sort du lot même si ça ne rentre pas dans des cases.</li>
<li>Ils ne vont pas écrire n&#8217;importe quoi dans l&#8217;annonce. Sérieux, quand je lis MailleSQL dans une annonce, j&#8217;ai envie de fesser les responsables.</li>
<li>C&#8217;est moins intimidant pour la personne qui répond à l&#8217;annonce. Parler à quelqu&#8217;un de son métier met à l&#8217;aise, et incite à postuler. Les dev sont parfois peu sociables, il faut leur faciliter cette démarche.</li>
</ul>
<p>Bien entendu, il est important que les RH les accompagnent dans le processus. Les techos n&#8217;y connaissent rien en recrutement. C&#8217;est un travail d&#8217;équipe. Mais ils doivent être ce qui est mis en avant, le premier filtre, et le dernier mot.</p>
<h2>Les infos importantes</h2>
<p>Trop souvent je vois des annonces qui ne listent pas les infos essentielles. Voici une liste des choses qui DOIVENT figurer sur l&#8217;annonce :</p>
<ul>
<li>Moyen de contact par email ET par téléphone. Nom de la personne qui va répondre, et poste.</li>
<li>Missions principales en 3 points : le sujet sur lequel on va travailler, quel rôle on va jouer, et les technos utilisées.</li>
<li>Talents requis, humains et techniques.</li>
<li>Échelle de rémunération.</li>
<li>Conditions de travail : équipe que l&#8217;on va intégrer (taille et rôle), localisation géographique du bureau, télétravail possible, etc.</li>
<li>Repères temporels : date de l&#8217;annonce, date de recrutement souhaitée, durée du contrat.</li>
</ul>
<p>A l&#8217;inverse, supprimez le bruit : expressions à la mode, jargon corporate, formules toutes faites&#8230; Les devs sont sensibles à ce genre de chose, et il est facile de passer pour des charlots en voulant rajouter du nutella sur la confiture.</p>
<p>Les trucs à oublier :</p>
<ul>
<li>&#8220;leader du marché&#8221;, &#8220;en forte croissance&#8221;, et toute autre auto congratulation. On s&#8217;en branle.</li>
<li>&#8220;projet innovant&#8221;, &#8220;révolutionner&#8221;, &#8220;so excited&#8221; et autres promesses que vous n&#8217;êtes pas capable de tenir. L’enthousiasme, vous le communiquez à l&#8217;entretien. Là ça fait vendeur de tapis Apple.</li>
<li>&#8220;vous êtes passionnés&#8221;, &#8220;un ninja&#8221;, &#8220;un killer&#8221;. Vous recruteriez quelqu&#8217;un pour la compta, vous diriez ça franchement ?</li>
<li>Les termes vagues : &#8220;taille humaine&#8221; (donnez un nombre), &#8220;réactifs aux changements&#8221; (ça veut tout et rien dire), &#8220;challenge&#8221; (listez les défis, ne les qualifiez pas).</li>
</ul>
<p>Évitez que votre annonce ressemble à <a href="http://sametmax.com/les-annonces-hypes/">ça</a>.</p>
<h2>Soyez pragmatique</h2>
<p>Tous les parents trouvent qu&#8217;ils ont le plus beau bébé du monde, mais ils vous les cassent quand ils vous montrent les photos en vous clamant qu&#8217;il est fantastique.</p>
<p>Votre boîte pète peut-être du Chanel numéro 5 à vos yeux, mais à moins d&#8217;avoir une attractivité incroyable (auquel cas vous n&#8217;avez probablement pas besoin de mettre une annonce), tout le monde s&#8217;en fout.</p>
<p>Bref, n’exigez pas un bac+x pour votre poste, il n&#8217;en a très probablement pas besoin. Mettez uniquement les talents requis techniques et humains. Ceux indispensables. Oubliez la limite d&#8217;âge, de diplôme et autres caractéristiques purement sociétales.</p>
<p>La seule chose qui compte, c&#8217;est que le mec fasse son job, et ça, il n&#8217;y a qu&#8217;un moyen de le vérifier : le voir bosser. Donc préparez des tests techniques, et organisez la période d&#8217;essai. Souvenez-vous qu&#8217;un gars débrouillard se formera sur le tas sans problème en info, c&#8217;est l&#8217;essence de notre taff.</p>
<p>Enfin, si vous voulez un mec bon, il va falloir se montrer attractif. On lui proposera 80k à Londres pour le même poste, trouvez un moyen de matcher ça.</p>
<p>Et si vous voulez un crack, souvenez-vous qu&#8217;il peut avoir 200k aux US. Le fait qu&#8217;il soit en France montre qu&#8217;il est intéressé par autre chose que l&#8217;argent. Cherchez ce que c&#8217;est, et tentez de devenir attractif en rapport avec ce point. Il y a bien d&#8217;autres choses que du pognon : télétravail, horaires flexibles, matériel de qualité, aide pour la famille s&#8217;il a des mômes, responsabilités inhabituelles pour quelqu&#8217;un d&#8217;aussi jeune, etc.</p>
<p>Mais la plupart du temps <strong>vous n&#8217;avez pas besoin d&#8217;un tueur</strong>. Vous avez besoin d&#8217;un mec normal, qui fait son boulot normalement. Alors ne faites pas votre processus de recrutement comme si vous cherchiez le prochain Linus Torvalds. Soyez réaliste, et vous trouverez plus rapidement ce dont vous avez besoin.</p>
<p>Je ne veux pas dire qu&#8217;il faut recruter n&#8217;importe quel boulet. Mettez les (nombreux) incompétents de côté rapidement, et efficacement, sans remord. Néanmoins, descendez de vos grands chevaux. Trop de recruteurs visent bien plus haut que ce dont ils ont besoin, mais aussi de ce qu&#8217;ils valent. Et de ce qu&#8217;ils peuvent payer.</p>
<p>L&#8217;offre et la demande ne sont pas en votre faveur, et ça ne va pas s&#8217;améliorer. Je vois tous les jours les résultats désastreux de mauvaises embauches, si vous voulez éviter ça, il faut se remettre en question.</p>
<h2>Exemple</h2>
<blockquote><p>Cherche Dev Backend Python</p></blockquote>
<p>Titre simple, court, qui permet d&#8217;être scanné facilement. Votre annonce ne sera pas lue par 99% des chercheurs, elle sera listée sur une page au milieu de centaines d&#8217;autres. Pour cette raison, mettez des mots-clés qui permettent facilement de la lister. &#8220;cherche&#8221;, &#8220;dev&#8221; et &#8220;python&#8221; font une query simple pour Google, Twitter, ou le meta moteur des sites de jobs.</p>
<blockquote><p>
Mon équipe de 3 dev a besoin d&#8217;un(e) pythonista pour travailler sur notre crawler de pages. La mission sera dans un premier temps de rajouter de nouvelles sources d&#8217;information à parser. Cela inclut une batterie de tests et de la documentation. D&#8217;autres tâches ponctuelles comme de la correction de bugs de notre ancien système et de la refactorisation des précédents crawlers sont à prévoir.
</p></blockquote>
<p>On commence par le quoi. C&#8217;est ce qui intéresse le plus la recrue, il veut savoir ce qu&#8217;il va foutre là-bas. Pas besoin de rentrer dans trop de détails, il faut juste en donner assez pour être clair, et pas trop pour l&#8217;inciter à appeler pour en savoir plus.</p>
<p>On utilise la première personne, ce qui donne un sentiment de proximité. &#8220;pythonista&#8221; est un terme spécifique à ce type de dev, montrant que l&#8217;annonce a été rédigée par quelqu&#8217;un qui s&#8217;y connaît.</p>
<blockquote><p>
Nous : LambdaBoite est spécialisée dans la vente de LambdaProduit, notre but étant de satisfaire LambdaBesoin de LambdaTypeDeClient.</p>
<p>Vous : on se fiche de savoir si vous avez 23 ans, portez des piercings ou si vous êtes sur une chaise roulante pourvu que vous livriez les features à temps.
</p></blockquote>
<p>On présente rapidement l&#8217;entreprise de manière générale. Un lien vers une page plus détaillée peut être inséré. On note les exigences humaines. Si la ponctualité est importante, mettez le. Ces lignes sont la relation personnelle que vous voulez établir. C&#8217;est vous, et lui/elle. C&#8217;est aussi le moment de mettre les recrues à l&#8217;aise en faisant un contraste. Ici, c&#8217;est carte blanche. Si vous avez des valeurs, exposez les. Si vous avez des choses amusantes à dire, dites les. Si ce sont des phrases marketings dictées par le département com interne (&#8220;we value&#8230;&#8221;), faites-les sauter.</p>
<blockquote><p>
Profil technique :<br />
&#8211; Capable d&#8217;écrire en Python : un décorateur maison, un code téléchargeant des ressources en ligne avec gestion des erreurs, une interface en ligne de commande avec argparse.<br />
&#8211; sait créer et déployer un daemon sous Linux Fedora en prod via supervisor.<br />
&#8211; sait faire une branche et un merge git.<br />
Vous serez testé à l&#8217;entretien.<br />
Sur place vous travaillerez avec :<br />
&#8211; de la programmation asynchrone.<br />
&#8211; PosGres.<br />
&#8211; Le framework Scrapy.<br />
Ces notions ne seront pas testées, vous pourrez les apprendre sur le tas.</p>
</blockquote>
<p>Plutôt que d&#8217;utiliser des termes vagues comme &#8220;bon niveau&#8221;, &#8220;senior&#8221;, etc., donnez des moyens précis de mesurer un niveau. Notez qu&#8217;on ne parle pas de diplôme ici. Le meilleur prog que je connais a Bac -2.</p>
<p>On sépare l&#8217;indispensable du &#8220;est un plus&#8221;. Mais plutôt que de le tourner en exigence, on le liste comme quelque chose d&#8217;attractif.</p>
<blockquote><p>
Date de recrutement souhaitée : 3 mars<br />
Contrat : CDD dans un premier temps, possible recrutement en CDI.<br />
Rémunération : 30-40k<br />
Contact : wololo@lambdaboite.com ou 0123456789 (Linette Michalon, CTO et votre futur boss)<br />
Adresse : 69 avenue du coin de la rue 69777 La villette sur roustifailles (votre bureau vous y attend)<br />
Site Web : http://lambdaboite.com/travaillez-chez-nous
</p></blockquote>
<p>Nature du contrat, contact avec qui, quoi et où puis lien vers une carte.</p>
<p>On notifie que l&#8217;adresse est bien l&#8217;endroit où l&#8217;on va travailler et pas juste le centre administratif.</p>
<p>Un lien vers plus de détails sur les conditions de travail (temps pour se déplacer, transport, photos des bureaux, liens vers l&#8217;équipe, présentation des produits, etc) est bienvenu.</p>
<p>Et oui, rédiger une annonce prend du temps. Recruter correctement prend du temps.</p>
<h2>Copier / coller</h2>
<p>Comme je sais que les gens aiment bien les templates, voici la version intégrale, prête à être copiée.</p>
<p>Mais je déconseille de l&#8217;utiliser telle quelle. Tout comme un CV doit être réécrit pour chaque poste qu&#8217;on vise, une annonce doit l&#8217;être pour chaque poste qu&#8217;on veut pourvoir.</p>
<h3>Cherche Dev Backend Python</h3>
<p>Mon équipe de 3 dev a besoin d&#8217;un(e) pythonista pour travailler sur notre crawler de pages. La mission sera dans un premier temps de rajouter de nouvelles sources d&#8217;information à parser. Cela inclut une batterie de tests et de la documentation. D&#8217;autres tâches ponctuelles comme de la correction de bugs de notre ancien système et de la refactorisation des précédents crawlers sont à prévoir.</p>
<p>Nous : LambdaBoite est spécialisée dans la vente de LambdaProduit, notre but étant de satisfaire LambdaBesoin de LambdaTypeDeClient.</p>
<p>Vous : on se fiche de savoir si vous avez 23 ans, portez des piercings ou si vous êtes sur une chaise roulante pourvu que vous livriez les features à temps.</p>
<p>Profil technique :</p>
<p>&#8211; Capable d&#8217;écrire en Python : un décorateur maison, un code téléchargeant des ressources en ligne avec gestion des erreurs, une interface en ligne de commande avec argparse.<br />
&#8211; sait créer et déployer un daemon sous Linux Fedora en prod via supervisor.<br />
&#8211; sait faire une branche et un merge git.</p>
<p>Vous serez testé à l&#8217;entretien.</p>
<p>Sur place vous travaillerez avec :</p>
<p>&#8211; de la programmation asynchrone.<br />
&#8211; PosGres.<br />
&#8211; Le framework Scrapy.</p>
<p>Ces notions ne seront pas testées, vous pourrez les apprendre sur le tas.</p>
<p>&#8212;&#8212;&#8212;-</p>
<p>Contrat : CDD dans un premier temps, possible recrutement en CDI.<br />
Rémunération : 30-40k.<br />
Contact : wololo@lambdaboite.com ou 0123456789 (Linette Michalon, CTO et votre futur boss)<br />
Adresse : 69 avenue du coin de la rue 69777 La villette sur roustifailles (votre bureau vous y attend)<br />
Site Web : http://lambdaboite.com/travaillez-chez-nous</p>
<h2>Sortir du cadre</h2>
<p>Ce que je viens de faire là, c&#8217;est une annonce générique. La vérité c&#8217;est que je n&#8217;écrirais pas une annonce comme ça moi-même. Une fois que vous avez maîtrisé ce qui est important pour vous et la recrue, vous pouvez adapter le style pour en faire quelque chose de plus personnel, et souvent plus court. L&#8217;idéal est de faire transparaître l&#8217;état d&#8217;esprit de la boîte via l&#8217;annonce.</p>
<p>Bon évidemment si vous recrutez pour une énorme boîte dinosaure type EDF, vous êtes baisé. </p>
<p>Pour finir, n&#8217;oubliez pas que l&#8217;annonce n&#8217;est pas la manière à préférer pour recruter. Le bouche à oreille, les événements techniques (conf, rassemblements, etc.), les sites communautaires et même les restos / bars sont de bien meilleurs sources. Donc mettez une annonce en ligne, puis allez à la Pycon à Lyon la semaine prochaine ou allez boire un verre au Cardinal sur Richelieu à Paname. Ca marche mieux.</p>


feed_id: http://sametmax.com/?p=12510
title: Le cercle de ses amis
uri: Le-cercle-de-ses-amis
url: http://sametmax.com/le-cercle-de-ses-amis/
content:
<p>Aujourd&#8217;hui une jolie blonde m&#8217;a trollé en recrachant mon sperme dans mon nombril.</p>
<p>J&#8217;ai trouvé ça hilarant, et j&#8217;ai éclaté de rire.</p>
<p>Elle a pris son sex toy et m&#8217;a dit : &#8220;je jouis encore une fois et on joue à Dota&#8221;. </p>
<p>Et je me suis occupé de ses seins pendant qu&#8217;elle s&#8217;occupait d&#8217;elle.</p>
<p>Je préfère ces moments là aux couchés de soleil, aux fleurs, aux restos avec bougies et aux boîtes de chocolat de la saint valentin.</p>
<p>L&#8217;humanité adore les clichés mais je pense qu&#8217;il appartient à tout à chacun de déterminer ce qu&#8217;on trouve charmant ou non. La partie coton, c&#8217;est de trainer avec des gens qui sont d&#8217;accord sur la question.</p>
<p>Je ne m&#8217;en fais pas trop sur le sujet.</p>
<p>J&#8217;ai Max pour me parler de la dernière thaï atomique qu&#8217;il a trouvé en VOIP.</p>
<p>J&#8217;ai un ami chinois qui m&#8217;a recommandé un super club échangiste alors qu&#8217;on surfait sur des sites de libertins.</p>
<p>J&#8217;ai une copine libanaise qui m&#8217;a signalé une bonne plage nudiste tandis qu&#8217;on mettait à jour son ordinateur sous Ubuntu.</p>
<p>J&#8217;ai un pote espagnol qui m&#8217;a raconté les envies de partouse de sa coloc avec son ex en jouant à LOL.</p>
<p>Geeks et cul, finalement, la formule du blog était pas si bête.</p>


feed_id: http://sametmax.com/?p=12524
title: Rapport de l&#8217;INDMS : le niveau des développeurs
uri: Rapport-de-l-INDMS-le-niveau-des-développeurs
url: http://sametmax.com/rapport-de-lindms-le-niveau-des-developpeurs/
content:
<p>Dans un article précédent, j&#8217;avais souligné la baisse du niveau des devs et on m&#8217;avait demandé mes sources. Mes sources, comme souvent pour ce genre d&#8217;opinion, sont les études empiriques du très sérieux Institut National du Doigt Mouillé de Sam. Faudrait que je fasse un logo mais je suis une pine en graphique.</p>
<p>Aujourd&#8217;hui, à l&#8217;aide de chiffres scientifiquement approximatifs et d&#8217;analyse d&#8217;échantillons représentatifs localement, à moins que ce soit l&#8217;inverse, nous allons vous expliquer ce qui se trame.</p>
<p>Je ne suis pro en dev que depuis 10 ans. 10 ans, c&#8217;est court dans une carrière. Mais en informatique, c&#8217;est long. Suffisamment long pour avoir vu l&#8217;ère pré-<code>msql_real_escape</code>, les premiers ORM, la mode du NoSQL et le big Data. Suffisamment pour avoir vu le design via <code>table</code>, puis la psychose du xHTML valide strict et accessible pour finir sur le HTML 5 avec le retour du JS inline qui ne sert pas qu&#8217;à faire des flocons de neige. Suffisamment pour avoir vu Linux devenir utilisable, la programmation sur téléphone accessible (vous vous souvenez qu&#8217;avant on programmait les nokias en J2ME ?), la latence réseau devenir un bottleneck, le CPU et la mémoire étant relégués à un problème comptable sur 90% des projets. Et surtout, suffisamment pour voir le Dev Web passer d&#8217;un truc de bidouilleur à une spécialité à part entière du monde de l&#8217;informatique.</p>
<p>Mais même avant, sans faire de l&#8217;argent avec, j&#8217;avais les mains dedans. J&#8217;avais un ordi avec des disquettes 5 pouces, un écran en noir et vert et un bouton &#8220;turbo&#8221; qui overclockait le puce à 8Mhz. Wooosh ! Et encore avant, un ordinateur avec une cassette à bande magnétique que je n&#8217;ai jamais réussi à faire marcher.</p>
<p>Et puis on croise du monde, des gens d&#8217;expérience qui partagent. On lit des livres d&#8217;il y a 20 ans (<a href="http://www.wordplace.com/ap/index.shtml">almost perfect</a> est disponible gratos au fait). On travaille. On forme. On recrute.</p>
<p>Cela m&#8217;a amené a plusieurs constats.</p>
<h2>Le niveau de vie des développeurs s&#8217;est bien amélioré</h2>
<p>Que ce soit au niveau qualité de matériel (2 écran HD pour utiliser VI, c&#8217;est le luxe), accessibilité de l&#8217;information (Google, c&#8217;est plus facile qu&#8217;un magazine ou des man pages sur disquette), automatisation (on compile très rarement les dépendances tierces maintenant), facilité de trouver un job (y a des annonces partout), tout est plus confortable.</p>
<p>Mais ce n&#8217;est pas le plus important.</p>
<p>L&#8217;image des dev s&#8217;est améliorée. Être le geek au collège n&#8217;était pas vraiment une partie de plaisir. En fait si j&#8217;avais rencontré Max dans la cour de l&#8217;école, on se serait probablement mis sur la gueule.</p>
<p>Aujourd&#8217;hui on vend des magazines avec en couv&#8217; des geeks millionnaires, Hollywood s&#8217;est approprié la mythologie du hacker et la coolification (devrais-je dire coolifitude ?) de l&#8217;utilisation informatique rend la vie beaucoup plus facile.</p>
<p>Quand je dis à une meuf que je suis informaticien, elle ne fuit plus. C&#8217;est pratique. La logistique devenait compliquée.</p>
<div id="attachment_12525" style="width: 310px" class="wp-caption aligncenter"><a href="media/c68de6c3.histo.png" data-original-source="http://sametmax.com/wp-content/uploads/2014/10/histo.png" class="grouped_elements" rel="tc-fancybox-group12524"><img src="media/b1abaa8f.histo-300x168.png" data-original-source="http://sametmax.com/wp-content/uploads/2014/10/histo-300x168.png" alt="Utilisation du piège à loup en % de rencards." width="300" height="168" class="size-medium wp-image-12525" /></a><p class="wp-caption-text">La dernière fois que Max a choisi une carrière d&#8217;un soir, il était chirurgien esthétique.</p></div>
<h2>L&#8217;informatique a explosé</h2>
<p>Comme vous pouvez le voir sur ce graphique, le nombre de connards à utiliser l&#8217;informatique a drastiquement augmenté. Ce faisant, il y a donc beaucoup plus d&#8217;appareils nécessitant d&#8217;être programmés sur le marché, les rayons, le chaumières et les poubelles.</p>
<div id="attachment_12526" style="width: 310px" class="wp-caption aligncenter"><a href="media/b455c332.courbes.png" data-original-source="http://sametmax.com/wp-content/uploads/2014/10/courbes.png" class="grouped_elements" rel="tc-fancybox-group12524"><img src="media/386a4385.courbes-300x168.png" data-original-source="http://sametmax.com/wp-content/uploads/2014/10/courbes-300x168.png" alt="Progression de la situation situationelle" width="300" height="168" class="size-medium wp-image-12526" /></a><p class="wp-caption-text">C&#8217;est toujours mauvais quand on croise les effluves</p></div>
<p>Malgré des échelles qui n&#8217;ont rien à voir, la courbe de facilité des usages suit paresseusement celles des usagers, et ce n&#8217;est pas un hasard. La formule pour calculer la simplicité d&#8217;un système étant dépendante de la variable du nombre de boulets l&#8217;utilisant (Evidence = MasseConnards²).</p>
<p>Or, pour répondre à la fois à la simplification des usages, et à leur multiplication, il y a fallu créer un paquets d&#8217;abstractions qui ont rajouté des couches, ce qui explique la progression du niveau d&#8217;indirection.</p>
<h2>Les formations n&#8217;ont pas suivi</h2>
<p>Dans le cas le plus grave, elles ont des années de retard sur les technologies actuellement utilisées. Dans le meilleur des cas, elles sont dispensées par des gens qui ne travaillent pas, et donc ne fournissent pas aux apprenants les éléments nécessaires pour être un élément productif.</p>
<div id="attachment_12527" style="width: 310px" class="wp-caption aligncenter"><a href="media/f9b8556c.pie.png" data-original-source="http://sametmax.com/wp-content/uploads/2014/10/pie.png" class="grouped_elements" rel="tc-fancybox-group12524"><img src="media/df7827c8.pie-300x168.png" data-original-source="http://sametmax.com/wp-content/uploads/2014/10/pie-300x168.png" alt="Enseignement uiversitaire en France" width="300" height="168" class="size-medium wp-image-12527" /></a><p class="wp-caption-text">Je voulais rajouter le pourcentage de profs qui avaient fait une migration de schéma en prod, mais LibreOffice n&#8217;accepte pas les chiffres négatifs.</p></div>
<p>Je voulais rajouter le pourcentage de profs qui avaient fait une migration de schéma en prod, mais LibreOffice n&#8217;accepte pas les chiffres négatifs.</p>
<p>Les bons informaticiens restent donc ceux qui se forment eux-mêmes. Via un projet personnel, par simple passion, en travaillant pour financer leurs études, etc. Même pendant la vie professionnelle, ceux qui ne deviennent pas obsolètes sont ceux qui continuent à apprendre. Car la formation en info, c&#8217;est toute sa vie. Et c&#8217;est un train où le paysage avance en même temps que soi, donc si on s&#8217;arrête, en vérité, on recule.</p>
<h2>Et du coup</h2>
<p>Le niveau des dev baisse. Pas de manière absolue, mais de manière relative au niveau dont le marché a besoin, et également en pourcentage de la population totale.</p>
<p>C&#8217;est lié à la conjoncture : plus de demande et plus de confort impliquent qu&#8217;il y a plus de monde qui se lance dedans. La démocratisation, c&#8217;est bien, mais ça apporte également un flot de personnes qui font ça comme job alimentaire. Or, si la formation ne suit pas, et qu&#8217;ils ne se forment pas, le nombre de technos continue d&#8217;augmenter. Les abstractions continuent de s&#8217;accumuler. Les nouveaux produits continuent de sortir.</p>
<p>Si bien que le besoin de dev augmente, mais également l&#8217;exigence de la somme des compétences requises progresse. Car si on a plus besoin de connaître la différence entre un little endian et un gros portoricain, pour dev une app Web moderne il faut maitriser : CSS, Javascript/Python/Ruby, HTML, quelques frameworks par dessus tout ça, une base de données et peut être un ORM, un système d&#8217;exploitation, potentiellement une machine virtuelle, un système de déploiement, des préprocesseurs, un système de files de tâches, un moteur de recherche, un système de cache&#8230;</p>
<p>Et l&#8217;attente des clients, comme des employeurs, sur le résultat, a elle aussi grandi. On veut du mieux, plus vite, plus ergonomique. Ils le font bien à côté. Par contre, ce qu&#8217;ils peuvent payer pour ça n&#8217;a pas beaucoup bougé en France, ils pensent toujours qu&#8217;avec un bon fichier de conf on peut faire faire un clone de Youtube pour pas cher.</p>
<p>Du coup les bons devs qui restent, ceux qui se sont formés et continuent de se former, ceux qui sont noyés dans la masse grandissante des spleenés de la programmation qu&#8217;on a attiré avec la promesse d&#8217;un job, ils se barrent. Ils se barrent là où on les paie à la hauteur de leur compétence : aux USA et aux UK.</p>
<p>Je résume :</p>
<ul>
<li>La demande en dev est en hausse.</li>
<li>A corréler avec l&#8217;augmentation du nombre d&#8217;abstractions.</li>
<li>Il y a plus de dev avec des boulots alimentaires.</li>
<li>Les meilleurs devs se cassent ou se mettent à leur compte.</li>
</ul>
<p>A l&#8217;embauche, le nombre de bons dev disponibles comparé à la demande grandissante et au nombre total de candidats, est en chute libre. Et ce, malgré le nombre de devs de talent, absolu, qui lui augmente dans le monde par le simple truchement de la démographie et de l&#8217;émulsion technologique.</p>
<p>Dans la vraie vie vivante, ça se traduit par des entretiens déprimants, des embauches tristes et des cours d&#8217;info frustrants.</p>
<p>Et la situation ne va pas s&#8217;arranger. Les besoins vont continuer à croître. Les bons dev ne vont pas sortir du chapeau. Faites en sorte que ce soit une bonne nouvelle pour vous :</p>
<ul>
<li>Si vous êtes dev, vous avez l&#8217;occasion de sortir du lot.</li>
<li>Si vous êtes recruteur, visez juste, et vous aurez un avantage concurrentiel non négligeable.</li>
</ul>
<p>Comment faire ? Arf, ça pourrait être un autre article. Un jour :)</p>


feed_id: http://sametmax.com/?p=12534
title: Rapatrier une branche d&#8217;un repo distant en local
uri: Rapatrier-une-branche-d-un-repo-distant-en-local
url: http://sametmax.com/rapatrier-une-branche-dun-repo-distant-en-local/
content:
<p>Vous avez un repo local et un remote. Une branche a été créée sur le remote, et vous voulez la récupérer en local :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #c20cb9; font-weight: bold;">git checkout</span> <span style="color: #660033;">--track</span> nom_du_remote<span style="color: #000000; font-weight: bold;">/</span>nom_de_la_branche</pre></td></tr></table></div>

<p>Par exemple :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #c20cb9; font-weight: bold;">git checkout</span> <span style="color: #660033;">--track</span> origin<span style="color: #000000; font-weight: bold;">/</span>dev</pre></td></tr></table></div>

<p>Ce qui va avoir pour effet de créer une branche &#8220;dev&#8221; sur votre repo local, de vous switcher dessus, et la lier à la branche &#8220;dev&#8221; du remote &#8220;origin&#8221;.</p>
<p>Comme d&#8217;hab, assurez-vous que votre copie de travail est bien propre avant sinon ça va merder au moment de changer de branche.</p>
<p>Ouais, ouais, je sais, <code>checkout</code> est la commande fourre-tout de git qui fait absolument n&#8217;importe quoi. C&#8217;est relou. </p>


feed_id: http://sametmax.com/?p=10490
title: Servir des fichiers statiques avec nginx
uri: Servir-des-fichiers-statiques-avec-nginx
url: http://sametmax.com/servir-des-fichiers-statiques-avec-nginx/
content:
<p>C&#8217;est un truc dont j&#8217;ai tout le temps besoin, alors l&#8217;article servira de pense bête. Marre de chercher à chaque fois :</p>
<pre>
        # sur django, on met tout dans /static/, donc par habitude je le fais
        # pour tout
        location /static/ {

            # Le dossier doit contenir le dossier 'static'. Par exemple si votre
            # arbo est /home/sametmax/repo/static, le chemin sera
            # /home/sametmax/repo. Rassurez-vous, personne n'aura accès aux
            # autres sous dossiers de "repo".
            root  /chemin/absolu/vers/dossier/;

            # On active la compression
            gzip  on;
            gzip_http_version 1.0;
            gzip_vary on;
            gzip_comp_level 6;
            gzip_proxied any;
            gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;
            gzip_buffers 16 8k;

            # Sauf pour les vieux nav
            gzip_disable ~@~\MSIE [1-6].(?!.*SV1)~@~];

            # On dit au navigateur de le mettre en cache pour 3 mois. Faites gaffe,
            # mettez un param dans les url de vos balises script/link qui change
            # à chaque version du fichier, sinon vous ne pourrez pas mettre à jour
            # vos fichiers.
            expires modified +90d;
        }
</pre>


feed_id: http://sametmax.com/?p=12561
title: AngularJS pour les utilisateurs de jQuery : partie 2
uri: AngularJS-pour-les-utilisateurs-de-jQuery-partie-2
url: http://sametmax.com/angularjs-pour-les-utilisateurs-de-jquery-partie-2/
content:
<p>Après une intro sans trop de code, on va passer à du concret.</p>
<p><span class='embed-youtube' style='text-align:center; display: block;'><iframe class='youtube-player' type='text/html' width='1170' height='689' src='http://www.youtube.com/embed/6Kbv1OpIpaA?version=3&#038;rel=1&#038;fs=1&#038;showsearch=0&#038;showinfo=1&#038;iv_load_policy=1&#038;wmode=transparent' frameborder='0' allowfullscreen='true'></iframe></span></p>
<p>Pour apprivoiser la bête, on va comme d&#8217;habitude lui faire donner la patte et dire bonjour :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="html" style="font-family:monospace;">&lt;!doctype html&gt;
&lt;!-- Lien entre l'app et la page --&gt;
&lt;html ng-app=&quot;tuto&quot;&gt;
  &lt;head&gt;
    &lt;meta charset=&quot;utf-8&quot; /&gt;
    &lt;title&gt;Hello Angular&lt;/title&gt;
    &lt;script src=&quot;https://ajax.googleapis.com/ajax/libs/angularjs/1.2.26/angular.js&quot;&gt;&lt;/script&gt;
    &lt;script type=&quot;text/javascript&quot;&gt;
&nbsp;
    // Déclaration de l'app
    var app = angular.module('tuto', [])
&nbsp;
    // Lancement du code quand angular est prêt
    app.run(function(){
        alert('Hello !')
    })
&nbsp;
    &lt;/script&gt;
  &lt;/head&gt;
  &lt;body&gt;
  &lt;/body&gt;
&lt;/html&gt;</pre></td></tr></table></div>

<p>Pour comprendre ce snippet, il faut réaliser qu&#8217;Angular est d&#8217;abord et avant tout un moyen d&#8217;organiser son code, et qu&#8217;il vous incite à le séparer en conteneurs :</p>
<ul>
<li>Des modules, qu&#8217;on appelle aussi apps. Ce sont les boîtes qui contiennent les autres boîtes. L&#8217;équivalent des apps Django, en fait : on peut mettre tout le programme dedans, mais on peut aussi en faire une lib réutilisable.</li>
<li>Les providers : des fournisseurs de services. Tout le code métier est dedans.</li>
<li>Les directives : tout le code de manipulation du DOM est dedans.</li>
<li>Les contrôleurs : fait le lien entre le HTML et les données.</li>
</ul>
<p>Dans ce code, nous déclarons un module (ou app, c&#8217;est kif-kif) nommé &#8220;tuto&#8221; et n&#8217;ayant aucune dépendance (le second paramètre est un array vide) :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="javascript" style="font-family:monospace;"><span style="color: #000066; font-weight: bold;">var</span> app <span style="color: #339933;">=</span> angular.<span style="color: #660066;">module</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'tuto'</span><span style="color: #339933;">,</span> <span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span></pre></td></tr></table></div>

<p>Les apps ne font pas grand chose. <strong>Ce sont de gros namespaces avec des dépendances</strong>, c&#8217;est à dire qui déclarent les autres apps nécessaires à leur fonctionnement. Par défaut, aucune autre app n&#8217;est obligatoire pour lancer notre code, donc on ne déclare aucune dépendance.</p>
<p>Il y a juste un piège qu&#8217;il faut connaître. Si je fais :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="javascript" style="font-family:monospace;"><span style="color: #000066; font-weight: bold;">var</span> app <span style="color: #339933;">=</span> angular.<span style="color: #660066;">module</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'tuto'</span><span style="color: #009900;">&#41;</span></pre></td></tr></table></div>

<p>(notez l&#8217;absence de second paramètre)</p>
<p>Angular va tenter de me chercher la référence d&#8217;app du nom de &#8220;tuto&#8221; qui existe déjà. L&#8217;absence de dépendance se note donc avec un array vide, et non l&#8217;absence d&#8217;array. Subtilité piégeuse s&#8217;il en est. Vu qu&#8217;on n&#8217;aura pas besoin de déclarer de dépendances avant longtemps, inutile de vous crisper dessus, je vous l&#8217;indique juste pour le débuggage qui va immanquablement arriver le jour où vous oublierez l&#8217;array vide.</p>
<p>Ensuite, on fait le lien entre notre code HTML et l&#8217;app via :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="html" style="font-family:monospace;">&lt;html ng-app=&quot;tuto&quot;&gt;</pre></td></tr></table></div>

<p><code>ng-app</code> est ce qu&#8217;on appelle une directive. Toutes les directives préfixées <code>ng-</code> sont fournies avec le framework et déjà chargées, prêtes à être utilisées. Une directive est un bout de code Javascript appliqué à du HTML, dans ce cas précis via un attribut.</p>
<p>Vous vous souvenez dans les années 2000 comme on vous faisait chier avec le fait de ne pas mettre de Javascript inline dans du HTML ? Les directives, c&#8217;est du Javascript inline qui ne dit pas son nom.</p>
<p><strong>Chaque page doit être liée à une app, et une seule.</strong> Si on ne met pas <code>ng-app</code>, notre code ne se chargera pas, si on en met 2, ça foire. C&#8217;est le point d&#8217;entrée de notre code. Nous déclarons donc que cette page sera gérée par notre app &#8220;tuto&#8221;.</p>
<p>Puis lance notre hello tonitruant :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="javascript" style="font-family:monospace;">    app.<span style="color: #660066;">run</span><span style="color: #009900;">&#40;</span><span style="color: #000066; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
        alert<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'Hello !'</span><span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span></pre></td></tr></table></div>

<p><code>app</code> est la variable contenant la référence à notre app, et en utilisant la méthode <code>.run</code>, on lui passe un <a href="http://sametmax.com/quest-ce-quun-callback/">callback</a> à appeler quand l&#8217;app sera prête.</p>
<p>Il y a plusieurs choses à réaliser ici :</p>
<ul>
<li>C&#8217;est un callback, donc le code de la fonction ne s&#8217;exécute pas tout de suite. Il sera lancé après l&#8217;initialisation de l&#8217;app.</li>
<li>C&#8217;est ce qu&#8217;il y a de plus proche du <code>$.ready</code> de jQuery.</li>
<li>On n&#8217;utilise presque jamais ce code avec Angular.</li>
</ul>
<p>Vous allez me dire, mais espèce de pignouf, pourquoi tu nous montres un code que personne n&#8217;utilise ?</p>
<p>Et bien parce que le titre du dossier est <em>AngularJS pour les utilisateurs de jQuery</em>, du coup je vous mets en terrain connu.</p>
<p>Mais la vérité, c&#8217;est qu&#8217;un vrai hello d&#8217;Angular ressemble à ça :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="html" style="font-family:monospace;">&lt;!doctype html&gt;
&lt;html ng-app=&quot;tuto&quot;&gt;
  &lt;head&gt;
    &lt;meta charset=&quot;utf-8&quot; /&gt;
    &lt;title&gt;Hello Angular&lt;/title&gt;
    &lt;script src=&quot;https://ajax.googleapis.com/ajax/libs/angularjs/1.2.26/angular.js&quot;&gt;&lt;/script&gt;
    &lt;script type=&quot;text/javascript&quot;&gt;
&nbsp;
    /* La je recréé l'app à chaque fois pour des raisons de praticité, mais
        dans un vrai code vous auriez ça dans un fichier à part, une seule
        fois */
    var app = angular.module('tuto', [])
&nbsp;
    // Création d'un controller, et attachement d'une variable au scope.
    app.controller('HelloCtrl', function($scope){
        // Attachement d'une donnée au scope
        $scope.hello = &quot;Hello&quot;
    })
&nbsp;
    &lt;/script&gt;
  &lt;/head&gt;
  &lt;body ng-controller=&quot;HelloCtrl&quot;&gt;
    &lt;!-- Affichage du message attaché au scope --&gt;
    &lt;h1&gt;{{ hello }}&lt;/h1&gt;
  &lt;/body&gt;
&lt;/html&gt;</pre></td></tr></table></div>

<p>Et là il y a beaucoup à dire.</p>
<p>Premièrement, contrairement à jQuery, il n&#8217;y a pas de notion de préparation du DOM. En vérité, on peut mettre son code Angular en vrac, et Angular va initialiser tout son monde dans le bon ordre, et exécuter ce qu&#8217;il faut au bon moment. Et ce bon moment est parfois avant que le DOM soit prêt.</p>
<p>Mais vous n&#8217;avez pas à vous en soucier.</p>
<p>Car avec Angular, on manipule très rarement le DOM. Très peu de <code>$('selecteur')</code>, <code>$node.bind()</code> et autre <code>$node.append()</code>, à part dans les directives.</p>
<p>La majorité de votre taf va être de définir des données en pur Javascript, de dire où elles vont dans la page, et de les manipuler en Javascript pendant qu&#8217;Angular s&#8217;occupe de mettre la page à jour automatiquement.</p>
<p>Nous avons pas mal de nouvelles notions ici. D&#8217;abord, le contrôleur&#8230;</p>
<p><strong>C&#8217;est un bout de code qu&#8217;on va lier à un bout de HTML</strong> via la directive <code>ng-controller</code> :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="html" style="font-family:monospace;">  &lt;body ng-controller=&quot;HelloCtrl&quot;&gt;
    ...
  &lt;/body&gt;</pre></td></tr></table></div>

<p>Le contrôleur va être responsable de mettre à disposition des données pour ce bout de HTML. On peut lier  autant de contrôleurs qu&#8217;on veut dans une page, et même les imbriquer. Ici, on dit que notre contrôleur <code>HelloCtrl</code> est responsable de mettre des données à disposition pour le tag <code>body</code> et tout ce qu&#8217;il contient.</p>
<p>On fait rarement des contrôleurs qui ratissent aussi large dans de vraies apps, mais pour notre exercice, c&#8217;est très bien.</p>
<p>Comment met-on à disposition des données ? Qu&#8217;est-ce que veut dire &#8220;mettre à disposition&#8221; ? Quelles données ?</p>
<p>Notre contrôleur ressemble à ceci :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="html" style="font-family:monospace;">    app.controller('HelloCtrl', function($scope){
        $scope.hello = &quot;Hello&quot;
    })</pre></td></tr></table></div>

<p>La fonction de callback sera exécutée quand <code>ng-controller="HelloCtrl"</code> sera activé automatiquement par Angular. Vous n&#8217;avez pas à vous souciez de quand, il le fera au moment le plus optimisé.</p>
<p>La seule chose dont vous avez à vous soucier, c&#8217;est ce que vous allez mettre dedans.</p>
<p>Et il y a ici deux nouvelles notions :</p>
<ul>
<li>L&#8217;injection de dépendances.</li>
<li>Le service (je vous explique ce qu&#8217;est un service plus loin) <code>$scope</code>.</li>
</ul>
<p>L&#8217;injection de dépendance fait partie de ces trucs qu&#8217;Angular fait automatiquement pour vous. Quand vous déclarez une variable dans le callback d&#8217;un contrôleur, Angular va chercher ce nom en mémoire, et récupérer le service qui porte ce nom. S&#8217;il ne le trouve pas, il plante.</p>
<p>Une fois qu&#8217;il a trouvé le service, il va attendre tranquillement le bon moment pour appeler le callback. Ce moment opportun arrivant, il va lui passer le service en paramètre. On dit qu&#8217;il lui &#8220;injecte&#8221; le service.</p>
<p>En relisant ces paragraphes, je réalise qu&#8217;il y a un mélange de plein de termes : contrôleurs, services, injection, bla, bla, bla.</p>
<p>Voilà le deal :</p>
<ol>
<li>Vous déclarez un contrôleur et vous le liez à du HTML via <code>ng-controlleur</code>.</li>
<li>Dans ce contrôleur vous dites &#8220;j&#8217;ai besoin du service Machin&#8221;</li>
<li>Angular cherche s&#8217;il connait Machin. Si non, il plante.</li>
<li>Angular prépare le HTML, décide qu&#8217;il est prêt, appelle votre contrôleur et lui passe Machin en paramètre automatiquement.</li>
</ol>
<p>Les services sont justes des d&#8217;objets javascript ordinaires, qu&#8217;on a nommés d&#8217;une certaine manière pour qu&#8217;Angular puisse les injecter. C&#8217;est tout.</p>
<p>En effet, pour résoudre le problèmes d&#8217;espace de nom en Javascript et d&#8217;organisation d&#8217;une grosse application, les créateurs d&#8217;Angular on créé un grand registre. On enregistre notre code dedans sous un nom (<code>Angular.module('nom_de_l_app')</code>, <code>app.controlleur('nom_du_controller')</code>, etc.), et Angular récupère le bon code au bon moment. C&#8217;est essentiellement un moyen de pallier au fait que Javascript est dégueulasse.</p>
<p>Donc, plutôt que de faire des imports comme en Python, on va déclarer une variable en paramètre, et Angular injecte le bon objet pour vous. C&#8217;est bizarre, mais on s&#8217;habitue.</p>
<p>Du coup, là :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="javascript" style="font-family:monospace;">app.<span style="color: #660066;">controller</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'HelloCtrl'</span><span style="color: #339933;">,</span> <span style="color: #000066; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span>$scope<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span></pre></td></tr></table></div>

<p>Je dis &#8220;crée moi le contrôleur nommé &#8216;HelloCtrl&#8217;, et quand tu vas appeler le callback, passe lui l&#8217;objet nommé &#8216;$scope&#8217; en paramètre. Fais ça au bon moment, je m&#8217;en branle, je veux pas le savoir. Démmerde toi, on a tous des problèmes.&#8221;</p>
<p>Le résultat, c&#8217;est que votre fonction sera exécutée automatiquement au bon moment, et qu&#8217;elle aura <code>$scope</code> qui lui sera passé.</p>
<p>Alors à quoi sert ce <code>$scope</code> ?</p>
<p>C&#8217;est simple : tout ce qui est attaché en attribut de <code>$scope</code> est accessible dans le HTML géré par ce contrôleur. Quand je fais :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="javascript" style="font-family:monospace;">    app.<span style="color: #660066;">controller</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'HelloCtrl'</span><span style="color: #339933;">,</span> <span style="color: #000066; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span>$scope<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
        $scope.<span style="color: #660066;">hello</span> <span style="color: #339933;">=</span> <span style="color: #3366CC;">&quot;Hello&quot;</span>
    <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span></pre></td></tr></table></div>

<p>Et que après je lie mon contrôleur au HTML :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="html" style="font-family:monospace;">  &lt;body ng-controller=&quot;HelloCtrl&quot;&gt;
    &lt;!-- Affichage du message attaché au scope --&gt;
    &lt;h1&gt;{{ hello }}&lt;/h1&gt;
  &lt;/body&gt;</pre></td></tr></table></div>

<p>Ma variable <code>hello</code> est disponible ici (via les petites moustaches qu&#8217;on verra au prochain chapitre), parce que je suis dans <code>body</code> qui est géré par le contrôleur <code>HelloCtrl</code> qui contient un <code>$scope</code> avec l&#8217;attribut <code>hello</code>. Fiou ! Ca en fait des couches. Mais Angular, c&#8217;est comme <del>un orgre</del> un onion.</p>
<p>Vous touchez ici du doigt l&#8217;essence même du boulot des contrôleurs, et à peu près leur unique but : mettre des données à disposition du HTML. C&#8217;est le C de <a href="http://sametmax.com/quest-de-que-mvc-et-a-quoi-ca-sert/">MVC</a>.</p>
<p>C&#8217;est pour cette raison que je vous ai répété &#8220;Angular va tout faire au bon moment, vous n&#8217;avez pas à vous soucier de quand&#8221;. Ceci est en effet très frustrant à entendre quand on vient du monde de jQuery puisque qu&#8217;on doit savoir exactement quand on fait les choses : il faut que le DOM soit prêt, il faut que les éléments sur lesquels on travaille existent, il faut qu&#8217;on puisse récupérer des nodes et en ajouter.</p>
<p>Avec Angular, on ne fait rien de tout ça. On va déclarer ses données dans le contrôleur, et dire où elles doivent être mises dans la page. Angular se charge de faire le lien pour vous quand le HTML est prêt, quand le Javascript est chargé, quand les Dieux sont avec vous&#8230;</p>
<hr />
<a href="https://github.com/sametmax/codes-des-articles/tree/master/2014/octobre"><br />
Télécharger le code de l&#8217;article.</a></p>


feed_id: http://sametmax.com/?p=12584
title: Automatiser un peu plus SQLAlchemy declarative
uri: Automatiser-un-peu-plus-SQLAlchemy-declarative
url: http://sametmax.com/automatiser-un-peu-plus-sqlalchemy-declarative/
content:
<p>Avec l&#8217;intégration de l&#8217;interface déclarative d&#8217;SQLAlchemy, le projet Elexir est mort, et bien mort. Mais avec lui, la syntaxe la plus simple de déclaration pour cet ORM. En effet, par défaut, SQLA vous oblige à spécifier le nom de la table et l&#8217;attribut ID pour chaque classe :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">from</span> sqlalchemy <span style="color: #ff7700;font-weight:bold;">import</span> Column<span style="color: #66cc66;">,</span> Integer<span style="color: #66cc66;">,</span> String
<span style="color: #ff7700;font-weight:bold;">from</span> sqlalchemy.<span style="color: black;">ext</span>.<span style="color: black;">declarative</span> <span style="color: #ff7700;font-weight:bold;">import</span> declarative_base
<span style="color: #ff7700;font-weight:bold;">from</span> sqlalchemy <span style="color: #ff7700;font-weight:bold;">import</span> create_engine
&nbsp;
Base <span style="color: #66cc66;">=</span> declarative_base<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">class</span> Person<span style="color: black;">&#40;</span>Base<span style="color: black;">&#41;</span>:
    <span style="color: #808080; font-style: italic;"># explicit is better than... fuck it !</span>
    __tablename__ <span style="color: #66cc66;">=</span> <span style="color: #483d8b;">'person'</span> 
    <span style="color: #008000;">id</span> <span style="color: #66cc66;">=</span> Column<span style="color: black;">&#40;</span>Integer<span style="color: #66cc66;">,</span> primary_key<span style="color: #66cc66;">=</span><span style="color: #008000;">True</span><span style="color: black;">&#41;</span>
    name <span style="color: #66cc66;">=</span> Column<span style="color: black;">&#40;</span>String<span style="color: black;">&#40;</span><span style="color: #ff4500;">250</span><span style="color: black;">&#41;</span><span style="color: #66cc66;">,</span> nullable<span style="color: #66cc66;">=</span><span style="color: #008000;">False</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">class</span> Animal<span style="color: black;">&#40;</span>Base<span style="color: black;">&#41;</span>:
    __tablename__ <span style="color: #66cc66;">=</span> <span style="color: #483d8b;">'animal'</span>
    <span style="color: #008000;">id</span> <span style="color: #66cc66;">=</span> Column<span style="color: black;">&#40;</span>Integer<span style="color: #66cc66;">,</span> primary_key<span style="color: #66cc66;">=</span><span style="color: #008000;">True</span><span style="color: black;">&#41;</span> <span style="color: #808080; font-style: italic;"># Paie ton DRY</span>
    name <span style="color: #66cc66;">=</span> Column<span style="color: black;">&#40;</span>String<span style="color: black;">&#40;</span><span style="color: #ff4500;">250</span><span style="color: black;">&#41;</span><span style="color: #66cc66;">,</span> nullable<span style="color: #66cc66;">=</span><span style="color: #008000;">False</span><span style="color: black;">&#41;</span>
&nbsp;
engine <span style="color: #66cc66;">=</span> create_engine<span style="color: black;">&#40;</span><span style="color: #483d8b;">'sqlite:///db.db.db...db'</span><span style="color: black;">&#41;</span>
Base.<span style="color: black;">metadata</span>.<span style="color: black;">create_all</span><span style="color: black;">&#40;</span>engine<span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>SQLA est très flexible, et il existe des tas de raisons pour vouloir un PK ou un nom de table custo. Mais dans beaucoup de projets, le nom de la table peut être le nom de la classe, et la PK peut être un ID auto incrémenté.</p>
<p>Heureusement, la lib vous permet de customiser absolument tout, même la manière dont on doit la customiser. Si c&#8217;est pas méta, tout ça&#8230;</p>
<p>Bref, on peut créer sa propre base déclarative qui va faire tout ça pour nous :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">from</span> sqlalchemy.<span style="color: black;">ext</span>.<span style="color: black;">declarative</span> <span style="color: #ff7700;font-weight:bold;">import</span> as_declarative<span style="color: #66cc66;">,</span> declared_attr
&nbsp;
<span style="color: #808080; font-style: italic;"># Ceci sera le parent de tout nos objets</span>
<span style="color: #66cc66;">@</span>as_declarative<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">class</span> Base<span style="color: black;">&#40;</span><span style="color: #008000;">object</span><span style="color: black;">&#41;</span>:
&nbsp;
    <span style="color: #808080; font-style: italic;"># Vu qu'on a pas vraiment envie de se réécrire la</span>
    <span style="color: #808080; font-style: italic;"># métaclasse, SQLA nous file ce gentil décorateur </span>
    <span style="color: #808080; font-style: italic;"># pour déclarer des attributs qui ne sont pas des </span>
    <span style="color: #808080; font-style: italic;"># champs</span>
    <span style="color: #66cc66;">@</span>declared_attr
    <span style="color: #ff7700;font-weight:bold;">def</span> __tablename__<span style="color: black;">&#40;</span>cls<span style="color: black;">&#41;</span>:
        <span style="color: #808080; font-style: italic;"># le nom de la table est le nom de la classe</span>
        <span style="color: #ff7700;font-weight:bold;">return</span> cls.__name__.<span style="color: black;">lower</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
    <span style="color: #808080; font-style: italic;"># L'id c'est la vie</span>
    <span style="color: #008000;">id</span> <span style="color: #66cc66;">=</span> Column<span style="color: black;">&#40;</span>Integer<span style="color: #66cc66;">,</span> primary_key<span style="color: #66cc66;">=</span><span style="color: #008000;">True</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">class</span> Person<span style="color: black;">&#40;</span>Base<span style="color: black;">&#41;</span>:
    name <span style="color: #66cc66;">=</span> Column<span style="color: black;">&#40;</span>String<span style="color: black;">&#40;</span><span style="color: #ff4500;">250</span><span style="color: black;">&#41;</span><span style="color: #66cc66;">,</span> nullable<span style="color: #66cc66;">=</span><span style="color: #008000;">False</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">class</span> Animal<span style="color: black;">&#40;</span>Base<span style="color: black;">&#41;</span>:
    name <span style="color: #66cc66;">=</span> Column<span style="color: black;">&#40;</span>String<span style="color: black;">&#40;</span><span style="color: #ff4500;">250</span><span style="color: black;">&#41;</span><span style="color: #66cc66;">,</span> nullable<span style="color: #66cc66;">=</span><span style="color: #008000;">False</span><span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>Evidemment il faut que vous soyez certains d&#8217;éviter les conflits liés à cette décision, mais c&#8217;est quand même vachement pratique.</p>


feed_id: http://sametmax.com/?p=12601
title: Des idées que j&#8217;aurai jamais le temps de faire.
uri: Des-idées-que-j-aurais-jamais-le-temps-de-faire
url: http://sametmax.com/des-idees-que-jaurais-jamais-le-temps-de-faire/
content:
<blockquote><p>Ceci est un post invité de <a href="http://recher.wordpress.com" target="_blank">Réchèr</a> sous licence <a href="http://creativecommons.org/licenses/by/3.0/" target="_blank">creative common 3.0 unported.</a></p></blockquote>
<p>Mon cerveau est absolument génial. Il trouve tout le temps un tas de projets super. Le problème c&#8217;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&#8217;est de l&#8217;offrir au monde.</p>
<p>Il y a un peu de tout : du potentiellement intéressant, du bien débile, et du carrément glauque. C&#8217;est en vrac, faites en ce que vous voulez.</p>
<p>Et puisque ça semble être une tradition pour les articles longs : un peu de musique.</p>
<p><span class='embed-youtube' style='text-align:center; display: block;'><iframe class='youtube-player' type='text/html' width='1170' height='689' src='http://www.youtube.com/embed/TboNW5AiHA8?version=3&#038;rel=1&#038;fs=1&#038;showsearch=0&#038;showinfo=1&#038;iv_load_policy=1&#038;wmode=transparent' frameborder='0' allowfullscreen='true'></iframe></span></p>
<h2>Chocolate DB</h2>
<p><em>&#8220;Maintenant, vous savez sur quoi vous allez tomber&#8221;</em></p>
<p><a href="media/9e6c5611.ipad_chocolate_ichocolates.jpg" data-original-source="http://sametmax.com/wp-content/uploads/2014/11/ipad_chocolate_ichocolates.jpg" class="grouped_elements" rel="tc-fancybox-group12601"><img src="media/d45fad4b.ipad_chocolate_ichocolates-300x256.jpg" data-original-source="http://sametmax.com/wp-content/uploads/2014/11/ipad_chocolate_ichocolates-300x256.jpg" alt="ipad_chocolate_ichocolates" width="300" height="256" class="alignnone size-medium wp-image-12603" /></a></p>
<p>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&#8217;islam ne boit plus d&#8217;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 &#8220;c&#8217;est écrit trop petit dessus&#8221;.</p>
<p>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, &#8230;</p>
<p>Si ça marche bien, on peut ensuite mettre en place un service d&#8217;échange entre personnes habitants à proximité. Deux machins dégeux à la noix de coco contre un succulent praliné au gianduja ? Ça marche !</p>
<p>Le concept est généralisable à tous ce qui se vend sous forme d&#8217;assortiment : yaourts aux fruits, sachets de thé, bonbons, bières, &#8230;</p>
<h2>Pub&#8217;homme</h2>
<p><a href="media/3141666f.toilet-paper-ad.jpg" data-original-source="http://sametmax.com/wp-content/uploads/2014/11/toilet-paper-ad.jpg" class="grouped_elements" rel="tc-fancybox-group12601"><img src="media/3ab954c7.toilet-paper-ad-300x225.jpg" data-original-source="http://sametmax.com/wp-content/uploads/2014/11/toilet-paper-ad-300x225.jpg" alt="toilet-paper-ad" width="300" height="225" class="alignnone size-medium wp-image-12605" /></a></p>
<p>Site web de contre-pouvoir à la publicité.</p>
<p>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é :</p>
<ul>
<li>hyperréalité</li>
<li>misandrie</li>
<li>sexualisation injustifiée</li>
<li>flatterie</li>
<li>association arbitraire avec une célébrité</li>
<li>&#8230;</li>
</ul>
<p>Sérieusement, quelqu&#8217;un pourrait me dire ce qu&#8217;il y a de sexuel dans un <a href="http://www.youtube.com/watch?v=9DIH-WYf9MY">putain de clacos</a> ?</p>
<p>Ensuite, il serait envisageable de créer des structures de soutien aux victimes de la publicité. Par exemple :</p>
<ul>
<li>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.</li>
<li>Les gens qui s&#8217;appellent Mégane Renault ou Zoé Renault.</li>
<li>Les parents dont les enfants font des caprices à cause des jouets qu&#8217;ils voient dans les publicités.</li>
</ul>
<p>(Parce que tout le monde n&#8217;est pas capable de se défendre aussi bien que <a href="http://www.liberation.fr/societe/2000/05/16/les-leneuf-entendus-par-la-justice-la-campagne-de-pub-de-9telecom-va-etre-temperee_326539">les Leneuf</a>).</p>
<p>Pour finir, on pourrait s&#8217;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 ?</p>
<h2>Un jeu web avec une économie déflationniste</h2>
<p><a href="media/202f84ac.WoW_stats.jpg" data-original-source="http://sametmax.com/wp-content/uploads/2014/11/WoW_stats.jpg" class="grouped_elements" rel="tc-fancybox-group12601"><img src="media/ffeec5ce.WoW_stats-300x146.jpg" data-original-source="http://sametmax.com/wp-content/uploads/2014/11/WoW_stats-300x146.jpg" alt="WoW_stats" width="300" height="146" class="alignnone size-medium wp-image-12608" /></a></p>
<p>Si vous lisez ce blog, vous connaissez déjà les bitcoins et les crypto-monnaies. L&#8217;une des raisons pour laquelle ce type de monnaie ne se démocratise pas, c&#8217;est qu&#8217;elles sont déflationnistes, un fonctionnement assez inhabituel. Un jeu web permettrait de le faire découvrir, d&#8217;expérimenter des situations, de détecter des comportements émergents, etc.</p>
<p>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&#8217;une ferme / d&#8217;un héros / d&#8217;un bar à gigolos &#8230; L&#8217;économie du jeu aurait les particularités suivantes :</p>
<ul>
<li>La quantité totale d&#8217;argent ne change jamais. Au départ, tout est dans la caisse commune du jeu. Pour l&#8217;exemple, mettons qu&#8217;il y ait un million de pièce d&#8217;or.</li>
<li>Les premiers joueurs inscrits reçoivent 100 pièces d&#8217;or, les suivants 50, les suivants-suivants 5, etc. (Au passage, ça incite à s&#8217;inscrire le plus tôt possible). Au bout d&#8217;un moment, les nouveaux arrivés ne reçoivent rien. Ce n&#8217;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.</li>
<li>Une pièce d&#8217;or est divisible à l&#8217;infini. Vous pouvez acheter une caisse de patates à 0.0000001 pièce d&#8217;or.</li>
<li>Pour que l&#8217;expérience soit complète, il faut que les joueurs puissent également faire du troc.</li>
</ul>
<p>Ce dernier point comporte un risque, car les joueurs pourront décider d&#8217;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&#8217;en pièces d&#8217;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&#8217;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.</p>
<h2>YourCryptoCoins</h2>
<p><a href="media/f202fd01.crypto-coins.jpeg" data-original-source="http://sametmax.com/wp-content/uploads/2014/11/crypto-coins.jpeg" class="grouped_elements" rel="tc-fancybox-group12601"><img src="media/f202fd01.crypto-coins.jpeg" data-original-source="http://sametmax.com/wp-content/uploads/2014/11/crypto-coins.jpeg" alt="crypto-coins" width="300" height="180" class="alignnone size-full wp-image-12606" /></a></p>
<p>Un logiciel simple pour créer sa propre crypto-monnaie, avec pleins de paramètres à ajuster, histoire de tester s&#8217;il y a plus efficace que le bitcoin :</p>
<ul>
<li>masse monétaire totale.</li>
<li>coût de transaction.</li>
<li>récompense par preuve de travail et/ou preuve de participation. Montant des récompenses.</li>
<li>difficulté de minage.</li>
<li>diminution automatique. (Tous les X jours, le solde de tous les comptes existants baissent de Y%, afin d&#8217;inciter les gens à dépenser leur argent)</li>
</ul>
<p>Ç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&#8217;arrache avec écrit &#8220;Soleil&#8221; dessus.</p>
<h2>Un réseau de communication vraiment décentralisé.</h2>
<p><a href="media/089f5990.semaphore.jpg" data-original-source="http://sametmax.com/wp-content/uploads/2014/11/semaphore.jpg" class="grouped_elements" rel="tc-fancybox-group12601"><img src="media/77869bdf.semaphore-300x195.jpg" data-original-source="http://sametmax.com/wp-content/uploads/2014/11/semaphore-300x195.jpg" alt="semaphore" width="300" height="195" class="alignnone size-medium wp-image-12610" /></a></p>
<p>Le problème d&#8217;internet, c&#8217;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.</p>
<p>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&#8217;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&#8217;identifiant de chaque point et éviter les usurpations d&#8217;identité.</p>
<p>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.</p>
<p>Ce serait sûrement très lent et pas fiable (si vos voisins n&#8217;ont pas allumé leurs transmetteurs, vous ne pouvez plus communiquer). Mais ce serait &#8220;libre&#8221;. Et du coup, pas d&#8217;abonnement à payer, juste de l&#8217;électricité.</p>
<p>C&#8217;est vraiment brumeux comme idée, parce que j&#8217;y connais rien en bidouilleries réseau. Si d&#8217;autres gens ont des améliorations à proposer, qu&#8217;ils n&#8217;hésitent pas.</p>
<h2>Poilatout</h2>
<p><a href="media/1877fc0a.cousin_machin.jpg" data-original-source="http://sametmax.com/wp-content/uploads/2014/11/cousin_machin.jpg" class="grouped_elements" rel="tc-fancybox-group12601"><img src="media/bcf39cb8.cousin_machin-214x300.jpg" data-original-source="http://sametmax.com/wp-content/uploads/2014/11/cousin_machin-214x300.jpg" alt="cousin_machin" width="214" height="300" class="alignnone size-medium wp-image-12611" /></a></p>
<p>Algorithme, qui, à partir d&#8217;une phrase donnée, renvoie le &#8220;poil au&#8221; correspondant.<br />
Exemple :<br />
<em>&#8220;Quand l&#8217;imbécile montre la Lune&#8221;</em><br />
 -> <em>&#8220;poil aux burnes&#8221;</em><br />
<em>&#8220;Le sage lui met un doigt&#8221;</em><br />
 -> <em>&#8220;poil au foie&#8221;</em></p>
<p>Y&#8217;a plus qu&#8217;à plugger ça avec Siri, et votre smartphone vous permettra de spammer toutes vos conversations de &#8220;poil au&#8221;.</p>
<p>Si ça sert à rien, c&#8217;est que c&#8217;est indispensable.</p>
<h2>Mi-tik</h2>
<p><em>&#8220;Trouvez votre moitié&#8221;.</em></p>
<p><a href="media/6c264e15.half_man_Andy_Gross.jpg" data-original-source="http://sametmax.com/wp-content/uploads/2014/11/half_man_Andy_Gross.jpg" class="grouped_elements" rel="tc-fancybox-group12601"><img src="media/6c264e15.half_man_Andy_Gross.jpg" data-original-source="http://sametmax.com/wp-content/uploads/2014/11/half_man_Andy_Gross.jpg" alt="half_man_Andy_Gross" width="186" height="159" class="alignnone size-full wp-image-12613" /></a></p>
<p>Vous êtes unijambiste de la jambe gauche. Vous vous inscrivez sur le site Mi-tik. Vous avez alors la possibilité d&#8217;être mis en relation avec des unijambistes de la jambe droite. Si vous trouvez quelqu&#8217;un qui vous correspond, vous obtenez 50% de réduction sur tous vos achats de chaussures.</p>
<p>Le site permet également de faire se rencontrer les manchots d&#8217;un bras, les borgnes, les &#8220;Van Gogh&#8221;, les hémiplégiques, &#8230;</p>
<h2>HarDis (Harcèlement Distribué).</h2>
<p><em>&#8220;Pensez dystopie globale, agissez dystopie locale&#8221;.</em></p>
<p><a href="media/ecd7bcad.dented-car-chuck-norris.jpg" data-original-source="http://sametmax.com/wp-content/uploads/2014/11/dented-car-chuck-norris.jpg" class="grouped_elements" rel="tc-fancybox-group12601"><img src="media/ecd7bcad.dented-car-chuck-norris.jpg" data-original-source="http://sametmax.com/wp-content/uploads/2014/11/dented-car-chuck-norris.jpg" alt="dented-car-chuck-norris" width="250" height="165" class="alignnone size-full wp-image-12614" /></a></p>
<p>La loi française ne vous interdit pas de chier sur le palier de votre voisin, de rayer sa voiture ou de l&#8217;appeler à 2 heures du matin. Mais elle vous interdit de le faire de manière répétée. Ça s&#8217;appelle du harcèlement.</p>
<p>Le &#8220;réseau d&#8217;entraide HarDis&#8221; permet de s&#8217;affranchir de ce détail. Vous vous y inscrivez en déclarant un périmètre géographique d&#8217;action. Vous recevez ensuite des missions, vous demandant d&#8217;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, &#8230;) et vous gagnez des points. Vous pouvez dépenser ces points pour créer des missions sur des gens que vous n&#8217;aimez pas.</p>
<p>L&#8217;identité et l&#8217;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&#8217;on effectue une mission et diminue lorsqu&#8217;on en prend une et qu&#8217;on ne l&#8217;effectue pas. Le but étant de limiter les &#8220;espions&#8221; (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).</p>
<p>Bien entendu, vous pouvez acheter des points, et bien entendu tous les outils d&#8217;anonymat sont disponibles : réseau Tor, crypto-monnaie, &#8230;</p>
<h2>ADN-Fuck</h2>
<p><em>&#8220;Là où y&#8217;a des gènes, y&#8217;a du plaisir&#8221;.</em></p>
<p><a href="media/0ef1e032.ensalada-de-pasta.jpg" data-original-source="http://sametmax.com/wp-content/uploads/2014/11/ensalada-de-pasta.jpg" class="grouped_elements" rel="tc-fancybox-group12601"><img src="media/34961064.ensalada-de-pasta-300x212.jpg" data-original-source="http://sametmax.com/wp-content/uploads/2014/11/ensalada-de-pasta-300x212.jpg" alt="ensalada-de-pasta" width="300" height="212" class="alignnone size-medium wp-image-12615" /></a></p>
<p>La société ADN-Fuck rachète vos petits déchets corporels : salive, poils, sang, peaux mortes, urine, sperme&#8230; Elle les mélange avec ceux de centaines de personnes, et revend le tout sous forme de petit sachet.</p>
<p>Quelqu&#8217;un souhaitant commettre un acte illégal peut acheter l&#8217;un de ces sachet d&#8217;anonymisation, et le répandre sur les lieux de son acte. Bonne chance à la police scientifique pour retrouver l&#8217;ADN du coupable !</p>
<p>La société ADN-Fuck en elle-même ne commet rien d&#8217;illégal. Le commerce de poils de cul est, à priori, toujours autorisé dans la plupart des régions du globe.</p>
<h2>RoboCraft</h2>
<p><a href="media/3a4a53ce.minecraft_robot.jpg" data-original-source="http://sametmax.com/wp-content/uploads/2014/11/minecraft_robot.jpg" class="grouped_elements" rel="tc-fancybox-group12601"><img src="media/ab9c6220.minecraft_robot-300x168.jpg" data-original-source="http://sametmax.com/wp-content/uploads/2014/11/minecraft_robot-300x168.jpg" alt="minecraft_robot" width="300" height="168" class="alignnone size-medium wp-image-12616" /></a></p>
<p>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.</p>
<p>Il y a déjà un add-on de Minecraft pour ça (ComputerCraft), mais c&#8217;est pas quelque chose de très officiel. Du coup, tout l&#8217;équilibrage du jeu est fait sans tenir compte de ComputerCraft. Un jeu conçu spécialement avec des robots, ce serait super chouette.</p>
<p>Ça rejoint le concept d&#8217;automatic-play, dont on parle ici ou là : <a href="http://gamestudies.org/1301/articles/depaoli_automatic_play">http://gamestudies.org/1301/articles/depaoli_automatic_play</a></p>
<p>Et il faudrait une économie déflationniste dans le jeu. Et des robots à reconnaissance vocale qui disent &#8220;poil au cul&#8221;.</p>
<h2>Multi-versus</h2>
<p><a href="media/b096ece0.multi_versus.jpg" data-original-source="http://sametmax.com/wp-content/uploads/2014/11/multi_versus.jpg" class="grouped_elements" rel="tc-fancybox-group12601"><img src="media/ad83ef79.multi_versus-300x102.jpg" data-original-source="http://sametmax.com/wp-content/uploads/2014/11/multi_versus-300x102.jpg" alt="multi_versus" width="300" height="102" class="alignnone size-medium wp-image-12617" /></a></p>
<p>Un jeu vidéo composé de mini-jeux, dans lequel deux joueurs ou plus s&#8217;affrontent, chacun avec un mini-jeux différent.</p>
<p>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&#8217;un coup, il envoie des lignes de cochonnerie sur l&#8217;aire de Tetris du joueur 1.</p>
<p>Ce n&#8217;est faisable qu&#8217;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.</p>
<h2>Un format de fichier pour décrire des dessins animés.</h2>
<p>Ce serait un format human-readable. C&#8217;est très important, car ça augmente la potentialité de bidouillage par n&#8217;importe qui, y compris des gamins de 8 ans.<br />
Ça pourrait ressembler à ceci par exemple :</p>
<pre>
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)
</pre>
<p>Et ça donnerait quelque chose de ce genre :</p>
<p><a href="media/f1075302.bounce_147.gif" data-original-source="http://sametmax.com/wp-content/uploads/2014/11/bounce_147.gif" class="grouped_elements" rel="tc-fancybox-group12601"><img src="media/f1075302.bounce_147.gif" data-original-source="http://sametmax.com/wp-content/uploads/2014/11/bounce_147.gif" alt="bounce_147" width="147" height="275" class="alignnone size-full wp-image-12619" /></a></p>
<p>Et ensuite, on pourrait faire plein de trucs avec ce format de fichier :</p>
<ul>
<li>des players web, des players desktop, des éditeurs, des extracteurs d&#8217;images,</li>
<li>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),</li>
<li>des options de sous-titres, de commentaires, d&#8217;audio-description, d&#8217;adaptation aux daltoniens et aux épileptiques,</li>
<li>des convertisseurs vers des fichiers vidéos classiques et vers du gif animé,</li>
<li>des méta-données pour les credits, la licence, le rating ESRB,</li>
<li>et bien d&#8217;autres choses encore !</li>
</ul>
<p>Vous allez me dire : &#8220;mais il y a déjà plein de trucs qui font ça : le flash, les gifs animés, Blender&#8230;&#8221;</p>
<p>Oui, sauf que le flash c&#8217;est pas libre, les gifs c&#8217;est pas optimisé et c&#8217;est super compliqué à reprendre et à bidouiller, et Blender, il faut des mois de pratique avant de savoir faire quelque chose de correct.</p>
<p>Ce format de fichier permettrait de créer rapidement des petits trucs à l&#8217;arrache, des cartes de vœux, des memes animés, etc. Et comme c&#8217;est du texte, c&#8217;est versionable et éditable collaborativement.</p>
<h2>Githubiser pleins de trucs.</h2>
<p><a href="media/8c265b3c.github-octocat.jpg" data-original-source="http://sametmax.com/wp-content/uploads/2014/11/github-octocat.jpg" class="grouped_elements" rel="tc-fancybox-group12601"><img src="media/03682427.github-octocat-300x244.jpg" data-original-source="http://sametmax.com/wp-content/uploads/2014/11/github-octocat-300x244.jpg" alt="github-octocat" width="300" height="244" class="alignnone size-medium wp-image-12620" /></a></p>
<p>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&#8217;un d&#8217;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 &#8220;Cher effect&#8221; et colle un flow de rap par dessus. Et ainsi de suite.</p>
<p>Ou alors, vous êtes un modéliseur 3D et vous commencez à créer un arbre géant. Quelqu&#8217;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&#8217;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.</p>
<p>Il y a plein d&#8217;autres trucs qu&#8217;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, &#8230; Et pour certains médias, le github de base, qui ne permet de traiter que du texte, ne suffit pas.</p>
<h2>Un Tolkien de la culture africaine</h2>
<p><a href="media/e4076de7.blackfoot-medicine-man-right.jpg" data-original-source="http://sametmax.com/wp-content/uploads/2014/11/blackfoot-medicine-man-right.jpg" class="grouped_elements" rel="tc-fancybox-group12601"><img src="media/c7b73841.blackfoot-medicine-man-right-250x300.jpg" data-original-source="http://sametmax.com/wp-content/uploads/2014/11/blackfoot-medicine-man-right-250x300.jpg" alt="blackfoot-medicine-man-right" width="250" height="300" class="alignnone size-medium wp-image-12621" /></a></p>
<p>Tolkien connaissait toutes les légendes de son pays et d&#8217;ailleurs. Il a défini la plupart des éléments de l&#8217;heroic fantasy. Sans lui, pas de Donjons et Dragons, de World of Warcraft, ou de Harry Potter. Maintenant, l&#8217;heroic fantasy vole de ses propres ailes et emprunte des éléments à d&#8217;autres cultures : momies égyptiennes, ninjas asiatiques, doppelgängers teutons, mind flayer lovecraftien, &#8230;</p>
<p>Mais à part les zombis, on trouve très peu de choses empruntés à la mythologie africaine. C&#8217;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&#8217;heroic fantasy.</p>
<p>Il faudrait une personne qui connaisse tous ces trucs (l&#8217;animisme, le vaudou, les totems, les esprits, &#8230;) et qui s&#8217;en inspire pour écrire une chiée de bouquins. Ensuite, les rôlistes, les gamers et J.K. Rowling feront le reste.</p>
<p><br/></p>
<p>Voilà, ce sera tout pour le moment. Phosphorez mes braves, phosphorez !! Et si l&#8217;une de ces idées existe déjà réellement, prévenez-moi, ça m&#8217;intéresse.</p>


feed_id: http://sametmax.com/?p=12632
title: Pas de bras et pas de chocolat
uri: Pas-de-bras-et-pas-de-chocolat
url: http://sametmax.com/pas-de-bras-et-pas-de-chocolat/
content:
<p>On avait pas d&#8217;articles, on a pas de forum, et on aura de nouveau pas d&#8217;articles.</p>
<p>C&#8217;est à peu près le résumé de ces derniers jours.</p>
<p>Je m&#8217;étais lancé dans l&#8217;installation de Discourse pour avoir un petit forum pour accompagner le blog, et du coup je n&#8217;ai pas écrit. </p>
<p>Mais c&#8217;est un FAIL. Et du coup on a pas de forum.</p>
<p>Foxmask et Gordon ont proposé d&#8217;installer ça sur leurs machines, du coup on aura peut être quelque chose quand ils auront fait leur bidouille.</p>
<p>Mais je me casse dans un endroit où je n&#8217;auras pas accès au téléphone ou internet pendant 10 jours, du coup y aura pas d&#8217;articles ces deux semaines non plus.</p>
<p>Du coup je fais un post bien long pour dire qu&#8217;il ne se passera rien, si c&#8217;est pas du vrai journalisme ça !</p>


feed_id: http://sametmax.com/?p=12648
title: Un peu de fun avec les décorateurs
uri: Un-peu-de-fun-avec-les-décorateurs
url: http://sametmax.com/un-peu-de-fun-avec-les-decorateurs/
content:
<p>Puisque la programmation asynchrone est au goût du jour, on se mange des callbacks un peu partout. Et ça alourdit toujours le code. Chaque langage, lib ou framework a essayé de trouver des astuces pour rendre tout ça plus digeste, et on a vu la naissance des Futures, Deferred, Promises, coroutines, yield from et autres joyeusetés.</p>
<p>Prenons par exemple un script Twisted. Déjà, Twisted, c&#8217;est pas vraiment l&#8217;exemple de la syntaxe Weight Watcher, ou alors si, mais avant le début du régime.</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #808080; font-style: italic;"># -*- coding: utf-8 -*-</span>
&nbsp;
<span style="color: #483d8b;">&quot;&quot;&quot; Télécharge des pages et affiche leur, de manière asynchrone &quot;&quot;&quot;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">re</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Ceci doit être pip installé</span>
<span style="color: #ff7700;font-weight:bold;">import</span> treq
<span style="color: #ff7700;font-weight:bold;">from</span> twisted.<span style="color: black;">internet</span>.<span style="color: black;">task</span> <span style="color: #ff7700;font-weight:bold;">import</span> react
<span style="color: #ff7700;font-weight:bold;">from</span> twisted.<span style="color: black;">internet</span>.<span style="color: black;">defer</span> <span style="color: #ff7700;font-weight:bold;">import</span> inlineCallbacks<span style="color: #66cc66;">,</span> returnValue
&nbsp;
<span style="color: #808080; font-style: italic;"># Soit on utilise la syntaxe 'inlineCallbacks', c'est à dire avec des yields</span>
<span style="color: #808080; font-style: italic;"># qui marquent les appels asynchrones.</span>
<span style="color: #66cc66;">@</span>inlineCallbacks
<span style="color: #ff7700;font-weight:bold;">def</span> get_title<span style="color: black;">&#40;</span>url<span style="color: black;">&#41;</span>:
    res <span style="color: #66cc66;">=</span> <span style="color: #ff7700;font-weight:bold;">yield</span> treq.<span style="color: black;">get</span><span style="color: black;">&#40;</span>url<span style="color: black;">&#41;</span> <span style="color: #808080; font-style: italic;"># Ceci est asynchrone et non bloquant</span>
    html <span style="color: #66cc66;">=</span> <span style="color: #ff7700;font-weight:bold;">yield</span> res.<span style="color: black;">content</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span> <span style="color: #808080; font-style: italic;"># Ça aussi</span>
    <span style="color: #ff7700;font-weight:bold;">try</span>:
        val <span style="color: #66cc66;">=</span> <span style="color: #dc143c;">re</span>.<span style="color: black;">search</span><span style="color: black;">&#40;</span>r<span style="color: #483d8b;">''</span><span style="color: #66cc66;">,</span> html.<span style="color: black;">decode</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'utf8'</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>.<span style="color: black;">groups</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#93;</span>
    <span style="color: #ff7700;font-weight:bold;">except</span>:
        val <span style="color: #66cc66;">=</span> <span style="color: #483d8b;">''</span>
&nbsp;
    returnValue<span style="color: black;">&#40;</span>val<span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Soit on récupère un objet defer et on ajoute un callback manuellement</span>
<span style="color: #ff7700;font-weight:bold;">def</span> main<span style="color: black;">&#40;</span>reactor<span style="color: black;">&#41;</span>:
&nbsp;
    <span style="color: #808080; font-style: italic;"># Ceci est asynchrone et non bloquant</span>
    defer <span style="color: #66cc66;">=</span> get_title<span style="color: black;">&#40;</span><span style="color: #483d8b;">'http://sametmax.com/quest-ce-quun-callback/'</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># Ceci arrive une fois que get_title est terminé</span>
    <span style="color: #ff7700;font-weight:bold;">def</span> cb<span style="color: black;">&#40;</span>title<span style="color: black;">&#41;</span>:
        <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span>title.<span style="color: black;">upper</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span> + <span style="color: #483d8b;">'!'</span><span style="color: black;">&#41;</span>
&nbsp;
    defer.<span style="color: black;">addCallback</span><span style="color: black;">&#40;</span>cb<span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># Pareil</span>
    autre_defer <span style="color: #66cc66;">=</span> get_title<span style="color: black;">&#40;</span><span style="color: #483d8b;">'https://github.com/sametmax/django-quicky'</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> cb<span style="color: black;">&#40;</span>title<span style="color: black;">&#41;</span>:
        <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span>title.<span style="color: black;">upper</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span> + <span style="color: #483d8b;">'!!!'</span><span style="color: black;">&#41;</span>
&nbsp;
    autre_defer.<span style="color: black;">addCallback</span><span style="color: black;">&#40;</span>cb<span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">return</span> defer
&nbsp;
react<span style="color: black;">&#40;</span>main<span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>D&#8217;une manière générale, je préfère la syntaxe à base de yields, même si elle oblige à se trimbaler le décorateur <code>inlineCallbacks</code> partout, à parsemer sa fonction de yields et à utiliser <code>returnValue</code> à la place de <code>return</code> puisque le mot clé est interdit dans les générateurs en Python 2.7.</p>
<p>Mais bon, ça reste facile à lire. On sait que les lignes avec <code>yield</code>, sont les appels bloquant qu&#8217;on demande à la boucle d’événements de traiter de manière asynchrone.</p>
<p>La syntaxe à base de callbacks est plus lourde, en revanche elle donne le contrôle sur la concurrence des callbacks puisqu&#8217;ils sont explicites au lieu d&#8217;être automatiquement ajoutés par magie. Elle parlera aussi plus aux dev Javascript qui ont l&#8217;habitude d&#8217;ajouter des callbacks manuellement.</p>
<p>Néanmoins, en JS, on a des fonctions anonymes plus flexibles, et on ferait donc plutôt une truc du genre :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;">get_title<span style="color: black;">&#40;</span>url<span style="color: black;">&#41;</span>.<span style="color: black;">then</span><span style="color: black;">&#40;</span>function<span style="color: black;">&#40;</span>title<span style="color: black;">&#41;</span><span style="color: black;">&#123;</span>
    <span style="color: #808080; font-style: italic;"># faire un truc avec le résultat</span>
<span style="color: black;">&#125;</span><span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>Et bien il se trouve qu&#8217;avec Python, bien qu&#8217;on ne le voit pas souvent, on peut avoir cette idée de la déclaration de son appel asynchrone juste au dessus de son callback, en utilisant des <a href="http://sametmax.com/comprendre-les-decorateurs-python-pas-a-pas-partie-1/">décorateurs</a>.</p>
<p>En effet, les décorateurs ne sont que du sucre syntaxique :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">@</span>truc
<span style="color: #ff7700;font-weight:bold;">def</span> bidule<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    chose</pre></td></tr></table></div>

<p>N&#8217;est en fait qu&#8217;un raccourci pour écrire :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">def</span> bidule<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    chose
&nbsp;
bidule <span style="color: #66cc66;">=</span> truc<span style="color: black;">&#40;</span>bidule<span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>Du coup, on peut prendre n&#8217;importe quelle fonction, ou méthode, et l&#8217;utiliser comme décorateur :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">@</span>react
<span style="color: #ff7700;font-weight:bold;">def</span> main<span style="color: black;">&#40;</span>reactor<span style="color: black;">&#41;</span>:
&nbsp;
    then <span style="color: #66cc66;">=</span> get_title<span style="color: black;">&#40;</span><span style="color: #483d8b;">'http://sametmax.com/quest-ce-quun-callback/'</span><span style="color: black;">&#41;</span>.<span style="color: black;">addCallback</span>
    <span style="color: #66cc66;">@</span>then
    <span style="color: #ff7700;font-weight:bold;">def</span> cb<span style="color: black;">&#40;</span>title<span style="color: black;">&#41;</span>:
        <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span>title.<span style="color: black;">upper</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span> + <span style="color: #483d8b;">'!'</span><span style="color: black;">&#41;</span>
&nbsp;
    then <span style="color: #66cc66;">=</span> get_title<span style="color: black;">&#40;</span><span style="color: #483d8b;">'https://github.com/sametmax/django-quicky'</span><span style="color: black;">&#41;</span>.<span style="color: black;">addCallback</span>
    <span style="color: #66cc66;">@</span>then
    <span style="color: #ff7700;font-weight:bold;">def</span> cb<span style="color: black;">&#40;</span>title<span style="color: black;">&#41;</span>:
        <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span>title.<span style="color: black;">upper</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span> + <span style="color: #483d8b;">'!!!'</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">return</span> cb</pre></td></tr></table></div>

<p>Et en jouant avec <code>functools.partial</code>, on peut faire aussi des trucs rigolos.</p>
<p>Non pas que cette syntaxe soit le truc indispensable à connaître et à utiliser. Mais les gens n&#8217;y pensent jamais. On utilise pas assez les décorateurs.</p>
<p>Par exemple, combien de fois vous avez vu :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">def</span> main<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'Doh'</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">if</span> __name__ <span style="color: #66cc66;">==</span> <span style="color: #483d8b;">'__main__'</span>:
    main<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>Certaines libs, comme begin, font des décorateurs pour ça :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">def</span> main<span style="color: black;">&#40;</span>func<span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">if</span> __name__ <span style="color: #66cc66;">==</span> <span style="color: #483d8b;">'__main__'</span>:
        func<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>Et du coup, dans son prog:</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">@</span>main
<span style="color: #ff7700;font-weight:bold;">def</span> _<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'Doh'</span><span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>Comme souvent, c&#8217;est le genre de feature qui peut être abusée, mais c&#8217;est parfois sympa de rapprocher une action juste au dessus de la fonction qui va être dans ce contexte.</p>
<p>J&#8217;espère ainsi vous avoir inspiré pour mettre un hack ou deux en production détournant complètement l&#8217;usage des décorateurs et ajoutant quelques gouttes de plus dans le vase de la sécurité de votre emploi, ou votre licenciement.</p>


feed_id: http://sametmax.com/?p=12659
title: 0bin s&#8217;est fait tej
uri: 0bin-s-est-fait-tej
url: http://sametmax.com/0bin-sest-fait-tej/
content:
<p>On a eu une take down notice pour une page 0bin, et comme on a pas réagit assez vite, on nous a juste coupé le site.</p>
<p>J&#8217;adore cette justice qui se passe de l&#8217;avis du système judiciaire, qui renverse la charge de la preuve et donne le pouvoir à des sociétés privées qui sont juges et parties. Je n&#8217;ai pas encore regardé la page en question, mais que ce soit légitime ou non, la démarche est aberrante.</p>
<p>Je vois bien Mac Do qui arrive chez un boucher :</p>
<blockquote><p>
Monsieur, nous pensons que votre steak imite le notre, nous fermons votre boutique jusqu&#8217;à ce que vous ne le vendiez plus. Non on a pas l&#8217;autorisation d&#8217;un juge, on est pas une société française de toute façon, on a juste fait pression sur le propriétaire de votre immeuble. Non, c&#8217;est pas mafieux si c&#8217;est légal, monsieur.
</p></blockquote>
<p>En plus, c&#8217;est pas comme si le système était pas déjà abusé par <a href="http://www.itworld.com/article/2734365/it-management/warner-brothers-abusing-dmca-takedown-rules.html">les ayant droits</a> ET <a href="http://korben.info/comment-google-livre-tete-d-une-activiste-aux-islamistes.html">les criminels</a>.</p>
<p>Bref, 0bin est down le temps qu&#8217;on répare tout ça.</p>


feed_id: http://sametmax.com/?p=12665
title: To shave or not to shave ?
uri: To-shave-or-not-to-shave
url: http://sametmax.com/to-shave-or-not-to-shave/
content:
<p>Le sexe fait parti de ces choses qui ne font pas l&#8217;unanimité. Pour rien.</p>
<p>Il n&#8217;y a qu&#8217;à lire les commentaires de nos articles d&#8217;opinion (<a href="http://sametmax.com/comment-tailler-une-pipe/">comment tailler une pipe</a>, <a href="http://sametmax.com/sol-do-mi-sol-do-mi-sol-do-mi/">la sodomie</a>, etc) pour illustrer les avis divergents sur la question.</p>
<p>Mais rien ne m&#8217;a semblé plus sujet à désaccord que la question de la pilosité.</p>
<p>Chez la femme, bien entendu, il y a l&#8217;épilation aisselles, jambes et maillot. Alors que les touffes sous les bras sont rarement un débat velu, le reste est déjà plus flou.</p>
<p>D&#8217;un côté, la majorité des hommes, selon un sondage officiel de l&#8217;INDMS, vous répondront qu&#8217;ils aiment la sensation de douceur d&#8217;un mollet imberbe. D&#8217;un autre, combien de gars se sont dit &#8220;nan, je vais trop pas coucher avec elle, elle est pas épilée&#8221;. J&#8217;en ai rencontré deux dans ma vie.</p>
<p>Détail amusant, quand on sait à quel point certaines meufs sont paniquées à l&#8217;idée de s&#8217;envoyer en l&#8217;air le premier soir si elles n&#8217;ont pas fait place nette. Surtout qu&#8217;un bas nylon coquinement gardé sera souvent fort apprécié, c&#8217;est dire si le mâle n&#8217;est pas difficile à satisfaire.</p>
<p>Mais le plus houleux, c&#8217;est la teuch.</p>
<p>Parce que si le film adulte main stream s&#8217;est mis à montrer des abricots chauves partout, ce n&#8217;est pas un hasard, c&#8217;est le résultat d&#8217;un ajustement au marché. Mais dans la VVV, on rencontre de tout. Ceux qui aiment avec, sans, en ticket de métro ou avec juste un pompon pour le clito. Une chance sur cinq de déplaire, selon notre échantillon représentatif de 5 personnes au dîner d&#8217;hier.</p>
<p>Et là c&#8217;est compliqué. Parce qu&#8217;un type qui n&#8217;aime pas la forêt tropicale va sans doute sauter la case broutage de pelouse, une étape de jardinage qui a son importance. Quel dommage.</p>
<p>En prime, pour rendre les choses bien plus amusantes, c&#8217;est aussi une question de culture. Au japon, les nanas ont l&#8217;entre-jambes fleuri, c&#8217;est pas de la paresse, c&#8217;est la loi de l&#8217;offre et la demande. En revanche, certaines femmes musulmanes très voilées ont l&#8217;entre-cuisses lisse qui glisse. Délice ou vice ?</p>
<p>Chez l&#8217;homme, c&#8217;est comme d&#8217;hab, moins clair encore.</p>
<p>Déjà vous avez le problème de la calvitie, des poils de tronc et celui de porter la barbe qui se rajoutent. Il y toujours moyen de déplaire à 30% du public, quoi qu&#8217;on fasse.</p>
<p>Et comme le modèle marketing du mec torride est sans poil, jusque sur les coucougnettes, on pourrait penser que c&#8217;est aussi une représentation empiriquement choisie. Fi, on m&#8217;a demandé bien souvent de laisser se garnir mon service 3 pièces car &#8220;ça fait acteur porno sinon&#8221;. Comprenons donc bien, qu&#8217;il n&#8217;y aucune garantie d&#8217;aller dans le sens du poil.</p>
<p>Mais ne coupons pas les cheveux en quatre, que faire ?</p>
<p>Du pareto, bien sûr !</p>
<p>Je connaissais un gars qui disait, les poils, ça n&#8217;a sa place que sur la tête. Sans rentrer dans les extrêmes tirés par les cheveux, les hommes peuvent, plutôt que de se raser ou s&#8217;épiler, se tondre. Ça fait propre, mais pas trop. Ça demande de la maintenance, c&#8217;est sûr, et aussi de se promener avec une tondeuse, ce qui est bien relou. Il ne faut pas avoir un poil dans la main pour ce genre de chose.</p>
<p>Max a tenté l&#8217;épilation définitive des burnes avec une machine à utiliser chez soi. Aux dernières nouvelles il a abandonné en cours de route à son départ pour l&#8217;Asie. Je ne puis donc vous en dire plus.</p>
<p>On pourra se consoler en disant que c&#8217;est plus chiant encore pour les nanas. Tout arracher est en effet encore le pari le plus sûr. Au pire quelqu&#8217;un qui aime jouer sur gazon sera plus tolérant qu&#8217;un obsédé du terrain synthétique. Mais ça fait mal. Et ça coûte cher. Enfin les filles, attendez l&#8217;accouchement, c&#8217;est encore plus douloureux, et ça douille encore plus, sur environ 20 ans. La vie est injuste.</p>
<p>Je ne peux pas terminer cet article sans vous remercier de m&#8217;avoir lu.</p>
<p>Poil au cul.</p>
<p>Je ne suis pas désolé.</p>


feed_id: http://sametmax.com/?p=12677
title: Est-ce que tu peux rendre ça configurable ?
uri: Est-ce-que-tu-peux-rendre-ça-configurable
url: http://sametmax.com/est-ce-que-tu-peux-rendre-ca-configurable/
content:
<p>Il y a cette manie qui traîne, cette idée que si quelque chose n&#8217;est pas dans un fichier de configuration, un outil manque de souplesse. Que si il n&#8217;y a pas un <code>settings['truc']</code>, ça va être compliqué si on veut le changer plus tard.</p>
<p>Et dans de nombreux langages bas niveaux, ça se vérifie.</p>
<p>Mais quand on code en Python, Ruby, PHP ou Javascript, et d&#8217;autant plus avec des gros frameworks d&#8217;abstraction, <strong>le code est déjà une forme de configuration.</strong></p>
<p>Souvent les clients me demandent de découpler mon code pour le rendre plus souple, plus flexible. Avec des options pour le rendre configurable. Et c&#8217;est une bonne chose.</p>
<p>Cependant il faut comprendre qu&#8217;il y a déjà tellement de design patterns embarqués dans nos outils modernes (iterator, generator, indexable, sliceable&#8230;), tellement de facilités offertes par les paradigmes actuels (typage dynamique, late binding, duck typing, bytecode, etc.) qu&#8217;un programme qui n&#8217;a pas été écrit comme un porc propose déjà une large marge de manœuvre.</p>
<p>Il est vrai qu&#8217;avec l&#8217;expérience, on écrit plus vite un code de meilleur qualité, et que, naturellement, on a tendance à laisser des hooks par ci, des opportunités d&#8217;injecter des dépendances par là. Surtout si on fait des tests unitaires.</p>
<p>Néanmoins, trop souvent, il sera demandé de pouvoir &#8220;rendre cette partie adaptable&#8221;, &#8220;faire en sorte qu&#8217;ici on puisse switcher d&#8217;implémentation&#8221; ou &#8220;je veux pouvoir changer d&#8217;avis plus tard&#8221;.</p>
<p>On peut déjà le faire.</p>
<p>Je suis programmeur, Python me parle. Un bon dev de la même techno trouvant mon code pourra modifier une bonne partie de mon travail pour obtenir un résultat différent.</p>
<p>Il n&#8217;y a pas forcément besoin d&#8217;une entrée en plus dans le <code>.ini|json|conf|bak|old|~|/dev/null</code>, d&#8217;un paramètre <code>backend</code>, de 2 jours de taf de plus pour rendre adaptable quelque chose qui peut être édité facilement.</p>
<p>De nombreuse fois, il est plus aisé de modifier, casser, remplacer, et même copier / coller.</p>
<p>Ce n&#8217;est pas écrit dans les bouquins sur les bonnes pratiques, mais c&#8217;est notre métier de coder. On est bons pour ça. On est rapides. Efficaces.</p>
<p>Si la fonctionnalité est un besoin avéré qu&#8217;il faudra pouvoir activer et désactiver en prod, bien entendu, il faut une option.</p>
<p>Mais si il faut couvrir un besoin futur hypothétiquement potentiel, laissez le dev décider si c&#8217;est YAGNI, on peut gagner beaucoup en productivité en pariant que modifier le code quand le besoin se présentera est la démarche la plus simple.</p>
<p>L&#8217;équilibre entre la dette technique et la sur-ingénierie permet de garder un projet sur les rails.</p>


feed_id: http://sametmax.com/?p=12704
title: Créer un réseau ad hoc sous Windows 8
uri: Créer-un-réseau-ad-hoc-sous-Windows-8
url: http://sametmax.com/creer-un-reseau-ad-hoc-sous-windows-8/
content:
<p>On a pas toujours un switch sous la main, et pourtant, mettre deux ordinateurs en réseau peut se faire sentir. Ok, c&#8217;est pour faire une LAN, qui j&#8217;essaye de tromper là ?</p>
<p>La solution, c&#8217;est le réseau ad hoc, c&#8217;est à dire demander à son ordi d&#8217;être point d&#8217;accès WIFI et réseau local.</p>
<p>Sous Windows 7, c&#8217;est facile, panneau de config, réseaux et partages, 3 clics et ça roule.</p>
<p>Mais mon Windows 8 ne voyait pas le réseau, et j&#8217;ai steam installé dessus.</p>
<p>Du coup, on a cherché un moyen de faire le réseau depuis W8, et l&#8217;option a été retirée des GUI.</p>
<p>Heureusement, il reste la ligne de commande.</p>
<p>D&#8217;abord, vérifier que son matos supporte le mode ad hoc :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="bash" style="font-family:monospace;">netsh wlan show drivers</pre></td></tr></table></div>

<p>Dans la liste, il doit y avoir une ligne à propos d&#8217;un réseau hébergé avec marqué &#8220;oui&#8221;.</p>
<p>Si ce n&#8217;est pas le cas, fin du voyage. Sinon, on configure le réseau (les droits admins sont nécessaires) :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="bash" style="font-family:monospace;">netsh wlan <span style="color: #000000; font-weight: bold;">set</span> un_nom_de_reseau <span style="color: #007800;">mode</span>=allow <span style="color: #007800;">ssid</span>=un_ssid <span style="color: #007800;">key</span>=un_mot_de_passe</pre></td></tr></table></div>

<p>Quand on veut lancer le réseau :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="bash" style="font-family:monospace;">netsh wlan start un_nom_de_reseau</pre></td></tr></table></div>

<p>Quand on veut l&#8217;arrêter :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="bash" style="font-family:monospace;">netsh wlan stop un_nom_de_reseau</pre></td></tr></table></div>

<p>Et les autres systèmes peuvent le voir dans la liste des réseaux WIFI sous le nom de &#8220;un_ssid&#8221; avec le mot de passe &#8220;un_mot_de_passe&#8221;.</p>


feed_id: http://sametmax.com/?p=12709
title: Dans quels secteurs retrouve-t-on Python ces temps-ci ? &#160; Recently updated !
uri: Dans-quels-secteurs-retrouve-t-on-Python-ces-temps-ci-Recently-up
url: http://sametmax.com/dans-quels-secteurs-retrouve-t-on-python-ces-temps-ci/
content:
<p>J&#8217;utilise le <a href="https://twitter.com/sam_et_max">compte Tweeter du blog</a> (n&#8217;oubliez pas qu&#8217;il y a un <a href="http://bridge.suumitsu.eu/?action=display&amp;bridge=TwitterBridge&amp;u=sam_et_max&amp;format=AtomFormat">flux RSS des tweets</a>) pour RT des offres d&#8217;emploi en rapport avec Python régulièrement. Des stages, des demandes de freelance, des embauches, etc. J&#8217;essaye de rester dans des offres francophones ou dans des pays limitrophes à la France, histoire que ce soit des infos utiles.</p>
<p>Ce faisant, j&#8217;ai pu noter au fil de l&#8217;année les secteurs qui sont le plus présents parmi ces recrutements, en tout cas via micro-blogging.</p>
<p>En premier, on a le Web, évidemment. Essentiellement du Django. Rien d&#8217;étonnant, ce n&#8217;est pas lié à Python en particulier, c&#8217;est juste le secteur informatique qui est le plus actif, et tout langage qui peut faire du HTTP correctement amène forcément du taf. Les outils pour cela en Python sont de bonne qualité, et on le retrouve donc un peu partout.</p>
<p>Ensuite vient la finance.</p>
<p>Ceci me gène un peu. Je ne les retweete pas en général, car éthiquement parlant, je ne suis pas à l&#8217;aise avec les institutions financières actuelles, mais ce n&#8217;est pas le sujet de l&#8217;article. Néanmoins ce sont d&#8217;excellentes opportunités techniques : analyse de données, temps réel, traitements logiques, UI, grosses infras, des moyens et un travail avec un impact fort IRL. Que Python s&#8217;impose dans ces milieux n&#8217;est pas une surprise : ils privilégient pragmatisme et efficacité. Or Python est un langage clair, qui permet une itération rapide en dev, des traitements complexes tout en restant facile à maintenir.</p>
<p>En 3ème position (selon les stats de l&#8217;INDMS, bien sûr), on retrouve la science : les chercheurs, biologistes, physiciens, géographes, astronomes et tous corps de métiers qui ont besoin de pouvoir adapter facilement des algos, transcrire des maths en code, traiter des gros jeux de données&#8230; Python est un langage fantastique pour cela, et sont apparues tout un tas de libs, soit pour gagner en perf, soit pour coller aux règles du métier. On retrouve du coup le langage comme solution de scripting dans des logiciels pros comme les SIG, des bases de données moléculaires et autres gros morceaux. C&#8217;est un usage tellement important que la prochaine version va embarquer un nouvel opérateur mathématique pour multiplier les matrices : le <code>@</code>.</p>
<p>Et puis il y a l&#8217;admin système et l&#8217;automatisation. Python remplace Perl un peu partout, dès qu&#8217;un script bash ne suffit plus. Car Python est simplement plus lisible et maintenable que ces deux langages, et il est aussi maintenant plus versatile, grâce au travail de la communauté. Des initiatives comme <a href="http://www.openstack.org/">OpenStack</a> ont fait de Python un acteur majeur dans les solutions de déploiement, de cloud, d&#8217;archi distribuées. C&#8217;est néanmoins très spécialisé, et concurrentiel, et donc trouver un bon dev là dedans ne doit pas être facile.</p>
<p>Notre pénultième, c&#8217;est la gestion d&#8217;entreprise. Principalement à travers le produit <a href="https://www.odoo.com/">Odoo</a> (aka OpenERP) qui s&#8217;occupe de tout, du personnel aux clients en passant par la facturation. C&#8217;est un peu usine à gaz, mais ça vaut toujours mieux que SAP. Ceci dit, en dehors de cela, Python est un fantastique langage glu, du fait qu&#8217;il est capable de lire et générer de nombreux formats (MS Office, LibreOffice, PDF, images) et base de données (MySQL, PostGres, Oracle, Access, et d&#8217;autres plus obscures). On peut même parler certains protocoles de machines outils. Dans des usines qui ont 15 ans d&#8217;empilement technologique et de migrations avec des morceaux legacy qui traînent partout, ça change la vie. Surtout qu&#8217;on peut maintenant remplacer VB avec Python presque partout, y compris dans Excel.</p>
<p>En dernier, il y a le Big Data. Derrière ce mot pompeux se cache les analyses de données massives, l&#8217;intelligence artificielle et en fait, tout ce qui concerne extraire du sens à partir d&#8217;un gros blob qui n&#8217;appartient pas aux métiers cités précédemment. Interprétation du langage humain, études d&#8217;images ou de son, réseaux sémantiques, généralement sous forme de grandes collections d&#8217;échantillons. Là c&#8217;est du haut niveau, mais ça fait justement des postes intéressants.</p>
<p>Malgré <a href="http://kivy.org/">Kivy</a>, le <a href="http://www.raspberrypi.org/">Rasberry Py</a> et <a href="http://micropython.org/">Micro Python</a>, je ne vois pas encore le langage décoller dans l&#8217;embarqué, sur téléphone, sur l&#8217;internet des objets&#8230; <a href="http://sametmax.com/le-potentiel-de-wamp-autobahn-et-crossbar-io/">WAMP</a> va peut être changer la donne, mais pas tant que qu&#8217;on aura pas créé une API plus sexy.</p>
<p>Les jeux vidéos sont aussi un secteur qui manque de Python, et c&#8217;est dommage. On lui préfère souvent le Lua, à part dans quelques cas comme Civilisation ou Eve Online.</p>
<p>Apparemment Python paie bien, mais honnêtement j&#8217;en ferai pas un critère de choix : ces choses là changent. Si on veut de la thune, on fait du Cobol, emploi bien payé garanti.</p>


feed_id: http://sametmax.com/?p=12717
title: Un gros guide bien gras sur les tests unitaires en Python, partie 4 &#160; Recently updated !
uri: Un-gros-guide-bien-gras-sur-les-tests-unitaires-en-Python-partie-4
url: http://sametmax.com/un-gros-guide-bien-gras-sur-les-tests-unitaires-en-python-partie-4/
content:
<p>Python est un langage très pro, et il y a beaucoup, beaucoup d&#8217;outils pour faire des tests.</p>
<p><a href="http://sametmax.com/un-gros-guide-bien-gras-sur-les-tests-unitaires-en-python-partie-3/">Après avoir vu pytest</a>, un outil typiquement pythonique sont les doctests, des tests unitaires intégrés dans les <a href="http://sametmax.com/les-docstrings/">docstrings</a>.</p>
<p>Pour rappel, les docstrings, ce sont ces chaînes de caractères qu&#8217;on retrouve au début des modules, sous la signature des fonctions ou dans la définition des classes. Elles servent à la documentation de ceux-ci, ainsi on peut la lire dans le code, et dans les vraies docs car les outils standards savent les extraire.</p>
<p>Ça ressemble à ça :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">def</span> une_fonction<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    <span style="color: #483d8b;">&quot;&quot;&quot; Ceci est une docstring.
&nbsp;
        On peut la lire dans le code source, avec help() dans le shell ou
        dans les docs générés par pydoc et sphinx.
    &quot;&quot;&quot;</span>
    <span style="color: #ff7700;font-weight:bold;">pass</span></pre></td></tr></table></div>

<p>Et bien ces docstrings, on peut mettre des tests unitaires dedans formatés comme des sessions de shell Python. Cela permet de donner des exemples d&#8217;usage, tout en testant son code. C&#8217;est chouette.</p>
<p>Musique ?</p>
<p>Musique.</p>
<p><span class='embed-youtube' style='text-align:center; display: block;'><iframe class='youtube-player' type='text/html' width='1170' height='689' src='http://www.youtube.com/embed/hUSm87nvG3k?version=3&#038;rel=1&#038;fs=1&#038;showsearch=0&#038;showinfo=1&#038;iv_load_policy=1&#038;wmode=transparent' frameborder='0' allowfullscreen='true'></iframe></span></p>
<h2>Hello doctests</h2>
<p>Faire des doctests n&#8217;est pas bien compliqué car c&#8217;est du copier coller. On fait une session shell avec ce qu&#8217;on veut tester, et on copie-colle le tout dans la docstring. Fastoche.</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #808080; font-style: italic;"># on copie juste la session de shell tel quel</span>
<span style="color: #ff7700;font-weight:bold;">def</span> ajouter<span style="color: black;">&#40;</span>a<span style="color: #66cc66;">,</span> b<span style="color: black;">&#41;</span>:
    <span style="color: #483d8b;">&quot;&quot;&quot;
        &amp;gt;&amp;gt;&amp;gt; ajouter(1, 2)
        3
    &quot;&quot;&quot;</span>
    <span style="color: #ff7700;font-weight:bold;">return</span> a + b
&nbsp;
<span style="color: #808080; font-style: italic;"># et on demande à Python de parser les doctests. Directement dans votre fichier</span>
<span style="color: #808080; font-style: italic;"># de code. Si, si. Pas de fichier de tests à part.</span>
<span style="color: #ff7700;font-weight:bold;">if</span> __name__ <span style="color: #66cc66;">==</span> <span style="color: #483d8b;">&quot;__main__&quot;</span>:
    <span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">doctest</span>
    <span style="color: #dc143c;">doctest</span>.<span style="color: black;">testmod</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>On lance ensuite directement notre fichier de code :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="bash" style="font-family:monospace;">python mon_module.py</pre></td></tr></table></div>

<p>Et ça n&#8217;affiche absolument rien. C&#8217;est parce qu&#8217;il n&#8217;y a pas d&#8217;erreur. On peut avoir le topo en demandant un peu de verbosité avec <code>-v</code> :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="bash" style="font-family:monospace;">python mon_module.py <span style="color: #660033;">-v</span>
Trying:
    ajouter<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #000000;">1</span>, <span style="color: #000000;">2</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>
Expecting:
    <span style="color: #000000;">3</span>
ok
<span style="color: #000000;">1</span> items had no tests:
    __main__
<span style="color: #000000;">1</span> items passed all tests:
   <span style="color: #000000;">1</span> tests <span style="color: #000000; font-weight: bold;">in</span> __main__.ajouter
<span style="color: #000000;">1</span> tests <span style="color: #000000; font-weight: bold;">in</span> <span style="color: #000000;">2</span> items.
<span style="color: #000000;">1</span> passed and <span style="color: #000000;">0</span> failed.
Test passed.</pre></td></tr></table></div>

<p>Les doctests marchent purement en se basant sur le formatage texte. Python prendre la ligne avec <code>&gt;&gt;&gt;</code>, l&#8217;exécutera, si la ligne suivante ne contient pas de <code>&gt;&gt;&gt;</code>, il va comparer le résultat de l&#8217;exécution de la ligne précédente avec le contenu de la ligne qui la suit.</p>
<p>Ceci passe :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #483d8b;">&quot;&quot;&quot;
    &amp;gt;&amp;gt;&amp;gt; ajouter(1, 2)
    3
&quot;&quot;&quot;</span></pre></td></tr></table></div>

<p>Mais ceci échoue :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #483d8b;">&quot;&quot;&quot;
    &amp;gt;&amp;gt;&amp;gt; ajouter(1, 2)
    4
&quot;&quot;&quot;</span></pre></td></tr></table></div>

<p>Car le résultat AFFICHÉ dans le shell est 3, et non 4.</p>
<p>En cas d&#8217;échec, Python vous en dit un peu plus :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="bash" style="font-family:monospace;">python mon_module.py
<span style="color: #000000; font-weight: bold;">**********************************************************************</span>
File <span style="color: #ff0000;">&quot;mon_module.py&quot;</span>, line <span style="color: #000000;">6</span>, <span style="color: #000000; font-weight: bold;">in</span> __main__.ajouter
Failed example:
    ajouter<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #000000;">1</span>, <span style="color: #000000;">2</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>
Expected:
    <span style="color: #000000;">4</span>
Got:
    <span style="color: #000000;">3</span>
<span style="color: #000000; font-weight: bold;">**********************************************************************</span>
<span style="color: #000000;">1</span> items had failures:
   <span style="color: #000000;">1</span> of   <span style="color: #000000;">1</span> <span style="color: #000000; font-weight: bold;">in</span> __main__.ajouter</pre></td></tr></table></div>

<h2>Formater ses doctests</h2>
<p>Les doctests sont faits pour s&#8217;intégrer de manière transparente aux docstrings. On peut donc en mettre autant qu&#8217;on veut, au milieu du texte ordinaire de la docstring. Python se base sur les chevrons (<code>&gt;&gt;&gt;</code>) pour savoir quand commence un test, et le saut de ligne pour savoir quand ça se termine. Au delà de ça, le style est libre.</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">def</span> ajouter<span style="color: black;">&#40;</span>a<span style="color: #66cc66;">,</span> b<span style="color: black;">&#41;</span>:
    <span style="color: #483d8b;">&quot;&quot;&quot; Je peux mettre n'importe quoi ici.
&nbsp;
        Et ici aussi.
&nbsp;
        Puis intégrer des tests:
&nbsp;
        &amp;gt;&amp;gt;&amp;gt; ajouter(1, 2)
        3
        &amp;gt;&amp;gt;&amp;gt; ajouter(2, 2)
        4
&nbsp;
        Et un saut de ligne indique que les tests sont terminés. Mais je peux
        encore en ajouter après si je veux.
&nbsp;
        &amp;gt;&amp;gt;&amp;gt; ajouter(0, 0)
        0
&nbsp;
    &quot;&quot;&quot;</span>
    <span style="color: #ff7700;font-weight:bold;">return</span> a + b</pre></td></tr></table></div>

<p>Néanmoins, l’intérêt des doctests est de documenter son code à travers les tests, et donc on adoptera généralement un format tel que ace;:</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">def</span> ajouter<span style="color: black;">&#40;</span>a<span style="color: #66cc66;">,</span> b<span style="color: black;">&#41;</span>:
    <span style="color: #483d8b;">&quot;&quot;&quot; Additionne deux elements.
&nbsp;
        Exemple :
&nbsp;
            &amp;gt;&amp;gt;&amp;gt; # on peut mettre des commentaires ici
            &amp;gt;&amp;gt;&amp;gt; ajouter(1, 2) # ou là
            3
            &amp;gt;&amp;gt;&amp;gt; ajouter(2., 2) # fonctionne sur tous les types de nombre
            4.0
&nbsp;
        La fonction fonctionne en duck typing, et accepte donc tout objet
        qui possède la méthode magique __add__ :
&nbsp;
            &amp;gt;&amp;gt;&amp;gt; ajouter('a', 'b')
            'ab'
            &amp;gt;&amp;gt;&amp;gt; ajouter([1], [2])
            [1, 2]
    &quot;&quot;&quot;</span>
    <span style="color: #ff7700;font-weight:bold;">return</span> a + b</pre></td></tr></table></div>

<p>Notez comme il est agréable de lire cette docstring : on comprend tout de suite comment utiliser la fonction. En prime, ce sont des tests unitaires qui garantissent que notre fonction va continuer de fonctionner correctement et nous oblige à garder cette doc à jour.</p>
<p>On peut faire des imports dedans ou utiliser temporairement <a href="http://sametmax.com/debugger-en-python-les-bases-de-pdb/">pdb</a> pour debugger. N&#8217;importe quel code de shell est valide mais faites attention à ne pas démarrer des boucles infinies comme les event loops des GUI ou lib async.</p>
<p>Voici ce que donnerait l&#8217;exemple des articles précédents avec des docstests :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">def</span> get<span style="color: black;">&#40;</span>data<span style="color: #66cc66;">,</span> index<span style="color: #66cc66;">,</span> default<span style="color: #66cc66;">=</span><span style="color: #008000;">None</span><span style="color: black;">&#41;</span>:
    <span style="color: #483d8b;">&quot;&quot;&quot; Implémente l'équivalent de dict.get() pour les indexables.
&nbsp;
        Example :
&nbsp;
            &amp;gt;&amp;gt;&amp;gt; simple_comme_bonjour = ('pomme', 'banane')
            &amp;gt;&amp;gt;&amp;gt; get(simple_comme_bonjour, 0)
            'pomme'
            &amp;gt;&amp;gt;&amp;gt; get(simple_comme_bonjour, 1000, 'Je laisse la main')
            'Je laisse la main'
    &quot;&quot;&quot;</span>
    <span style="color: #ff7700;font-weight:bold;">try</span>:
        <span style="color: #ff7700;font-weight:bold;">return</span> data<span style="color: black;">&#91;</span>index<span style="color: black;">&#93;</span>
    <span style="color: #ff7700;font-weight:bold;">except</span> <span style="color: #008000;">IndexError</span>:
        <span style="color: #ff7700;font-weight:bold;">return</span> default</pre></td></tr></table></div>

<h2>Problèmes et solutions</h2>
<p>Les doctests ne sont pas la Panacée, particulièrement parce que le test se fera sur le résultat AFFICHÉ dans le shell. Cela peut facilement amener à des erreurs.</p>
<p>Déjà, il faut faire attention à la représentation des objets dans le shell Python. <strong>La représentation n&#8217;est pas forcément la valeur de saisie</strong> :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;">&amp;gt<span style="color: #66cc66;">;</span>&amp;gt<span style="color: #66cc66;">;</span>&amp;gt<span style="color: #66cc66;">;</span> <span style="color: #ff4500;">1</span>.
<span style="color: #ff4500;">1.0</span>
&amp;gt<span style="color: #66cc66;">;</span>&amp;gt<span style="color: #66cc66;">;</span>&amp;gt<span style="color: #66cc66;">;</span> <span style="color: #483d8b;">&quot;1&quot;</span>
<span style="color: #483d8b;">'1'</span>
&amp;gt<span style="color: #66cc66;">;</span>&amp;gt<span style="color: #66cc66;">;</span>&amp;gt<span style="color: #66cc66;">;</span> <span style="color: black;">&#123;</span><span style="color: #483d8b;">&quot;foo&quot;</span>: <span style="color: #483d8b;">&quot;bar&quot;</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">&quot;une apostrophe : '&quot;</span>: <span style="color: #483d8b;">&quot;est échapée ainsi qu'un accent&quot;</span><span style="color: black;">&#125;</span>
<span style="color: black;">&#123;</span><span style="color: #483d8b;">&quot;une apostrophe : '&quot;</span>: <span style="color: #483d8b;">&quot;est <span style="color: #000099; font-weight: bold;">\x</span>c3<span style="color: #000099; font-weight: bold;">\x</span>a9chap<span style="color: #000099; font-weight: bold;">\x</span>c3<span style="color: #000099; font-weight: bold;">\x</span>a9e ainsi qu'un accent&quot;</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'foo'</span>: <span style="color: #483d8b;">'bar'</span><span style="color: black;">&#125;</span></pre></td></tr></table></div>

<p>La solution à ce problème est de tester dans le shell les valeurs de retour, et non de le faire de tête. Faites bien gaffe aux espaces qui sont donc significatifs, surtout ceux en fin de ligne. Mon éditeur est configuré pour les virer par défaut, et ça m&#8217;a niqué en écrivant l&#8217;article :)</p>
<p>Ensuite, il y a des cas où la représentation ne sera pas la même d&#8217;un appel à l&#8217;autre.</p>
<p>C&#8217;est le cas avec les dictionnaires, puisque l&#8217;ordre des éléments n&#8217;est pas garanti par nature. Ne faites donc pas :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;">&amp;gt<span style="color: #66cc66;">;</span>&amp;gt<span style="color: #66cc66;">;</span>&amp;gt<span style="color: #66cc66;">;</span> retourne_un_dico<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
<span style="color: black;">&#123;</span><span style="color: #483d8b;">'ordre'</span>: <span style="color: #483d8b;">'non garanti'</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'le'</span>: <span style="color: #483d8b;">'resultat'</span><span style="color: black;">&#125;</span></pre></td></tr></table></div>

<p>Mais plutôt quelque chose qui vous garantit l&#8217;affichage :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #483d8b;">&quot;&quot;&quot;
&amp;gt;&amp;gt;&amp;gt; res = list(retourne_un_dico().items())
&amp;gt;&amp;gt;&amp;gt; res.sort()
[('le', 'resultat'), ('ordre', 'non garanti')]
&amp;gt;&amp;gt;&amp;gt; # ou
&amp;gt;&amp;gt;&amp;gt; retourne_un_dico() == {'ordre': 'non garanti', 'le': 'resultat'}
True
&quot;&quot;&quot;</span></pre></td></tr></table></div>

<p>Parfois, on ne peut juste pas garantir l&#8217;affichage. Par exemple avec des nombres non prévisibles comme les hash ou les id des objets :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #483d8b;">&quot;&quot;&quot;
&amp;gt;&amp;gt;&amp;gt; class Test(): pass
&amp;gt;&amp;gt;&amp;gt; repr(Test())
''
&quot;&quot;&quot;</span></pre></td></tr></table></div>

<p><code>7f4687d30fc8</code> n&#8217;est ici pas prévisible. Python met certains cas spéciaux comme celui-ci des flags activables via le commentaire <code># doctest: +NOM_DU_FLAG</code>.</p>
<p>Par exemple, le flag <code>ELLIPSIS</code> permet de placer <code>...</code> dans le résultat en guise de joker :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #483d8b;">&quot;&quot;&quot;
&amp;gt;&amp;gt;&amp;gt; repr(Test()) # doctest: +ELLIPSIS
''
&quot;&quot;&quot;</span></pre></td></tr></table></div>

<p>D&#8217;autres problèmes similaires peuvent être résolus ainsi. Le flag <code>SKIP</code> permet de sauter un test que vous voulez mettre là, en exemple, mais qui ne doit pas être testé :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #483d8b;">&quot;&quot;&quot;
&amp;gt;&amp;gt;&amp;gt; # ce test va être ignoré
&amp;gt;&amp;gt;&amp;gt; repr(Test()) # doctest: +SKIP
''
&quot;&quot;&quot;</span></pre></td></tr></table></div>

<p><code>NORMALIZE_WHITESPACE</code> permet de considérer toute séquence de caractères non imprimables comme un espace. 8 tabs ou 4 espaces dans le résultat seront tous considérés comme un espace.</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #483d8b;">&quot;&quot;&quot;
&amp;gt;&amp;gt;&amp;gt; 'ceci est une assez longue ligne divisible' # doctest: +NORMALIZE_WHITESPACE
'ceci    est     une assez longue    ligne divisible'
&quot;&quot;&quot;</span></pre></td></tr></table></div>

<p>Les flags sont cumulables, si on les sépare par des virgules dans le commentaire.</p>
<p>Autre astuce, si votre sortie doit contenir un saut de ligne, Python va l’interpréter comme la fin des tests. On peut pallier cela en utilisant <code>&lt;BLANKLINE&gt;</code> :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #483d8b;">&quot;&quot;&quot;
&amp;gt;&amp;gt;&amp;gt; print('Un saut de ligne<span style="color: #000099; font-weight: bold;">\\</span>n')
Un saut de ligne
&nbsp;
&quot;&quot;&quot;</span></pre></td></tr></table></div>

<p>Faites attention aux antislash et autres caractères spéciaux dans vos docstests puisque toute string est parsée deux fois : une fois à l&#8217;écriture de la docstring, puis une fois à son exécution. Ici vous voyez que je suis tenu d&#8217;échapper mon <code>\n</code> On peut d&#8217;ailleurs utiliser les préfixes <code>r</code> (cf: les <a href="http://sametmax.com/comment-marchent-les-raw-strings-en-python/">raw strings</a>) et <code>u</code> sur les docstrings, si un jour vous êtes bloqué par trop d&#8217;échappements ou des caractères non ASCII en pagaille, pensez-y.</p>
<p>Un cas particulier est celui des exceptions. LOL, n&#8217;est-il pas ?</p>
<p>Pour y répondre, Python décide qu&#8217;une expression est levée si il voit <code>Traceback (most recent call last):</code>. Il ignore ensuite tout le texte &#8211; qui est donc optionnel et que vous pouvez omettre &#8211; jusqu&#8217;à ce qu&#8217;il rencontre le nom de l&#8217;exception levée. À partir de là, il vérifie que le test passe.</p>
<p>Par exemple, si votre exception génère ce traceback :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;">Traceback <span style="color: black;">&#40;</span>most recent call last<span style="color: black;">&#41;</span>:
  File <span style="color: #483d8b;">&quot;&quot;</span><span style="color: #66cc66;">,</span> line <span style="color: #ff4500;">1</span><span style="color: #66cc66;">,</span> <span style="color: #ff7700;font-weight:bold;">in</span> 
  File <span style="color: #483d8b;">&quot;test.py&quot;</span><span style="color: #66cc66;">,</span> line <span style="color: #ff4500;">41</span><span style="color: #66cc66;">,</span> <span style="color: #ff7700;font-weight:bold;">in</span> ajouter
    <span style="color: #ff4500;">1</span> / <span style="color: #ff4500;">0</span>
<span style="color: #008000;">ZeroDivisionError</span>: integer division <span style="color: #ff7700;font-weight:bold;">or</span> modulo by zero</pre></td></tr></table></div>

<p>Vous pouvez faire dans votre doctest :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #483d8b;">&quot;&quot;&quot;
&amp;gt;&amp;gt;&amp;gt; je_leve_une_exception()
Traceback (most recent call last):
ZeroDivisionError: integer division or modulo by zero
&quot;&quot;&quot;</span></pre></td></tr></table></div>

<p>Seule la dernière ligne est comparée.</p>
<p>Il est également possible de mettre les doctests dans un fichier texte à part, mais je ne vous le recommande pas. Cela retire l’intérêt principal des doctests : avoir du code exécutable dans la doc. Si on doit avoir un fichier séparé, autant utiliser des tests normaux, bien plus pratiques et complets.</p>
<p>Car il n&#8217;y a pas de tear down, setup ou fixtures avec les docstests. Ca reste un outil basique.</p>
<p>Sachez néanmoins que les doctests sont parfaitement compris par <code>pytest</code>, il suffit juste de lui demander de les exécuter avec l&#8217;option suivante :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="bash" style="font-family:monospace;">py.test <span style="color: #660033;">--doctest-modules</span></pre></td></tr></table></div>

<p>Dans ce cas, il n&#8217;est pas nécessaire de faire à la fin de chaque fichier contenant des doctests :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">if</span> __name__ <span style="color: #66cc66;">==</span> <span style="color: #483d8b;">&quot;__main__&quot;</span>:
    <span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">doctest</span>
    <span style="color: #dc143c;">doctest</span>.<span style="color: black;">testmod</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span></pre></td></tr></table></div>

<h2>Quand utiliser les doctests ?</h2>
<p>Généralement, on utilise un mélange des tests ordinaires (dans notre cas des tests <code>pytest</code> plutôt que <code>unittest</code>) et des doctests.</p>
<p>On utilisera des doctests pour les objets ou les fonctions simples et indépendantes. J&#8217;entends par là, des fonctions et des objets qui prennent uniquement des types basiques en paramètres, et qui retournent uniquement ces types basiques en paramètres. Pour les objets, ils doivent avoir peu de méthodes.</p>
<p>Pour tout le reste, on utilisera des tests ordinaires.</p>
<p>Par exemple, si vous avez une fonction comme notre exemple <code>get()</code>, les doctests sont un bon choix. En revanche, si vous avez un objet <code>Server</code> qui est un serveur HTTP, ou une fonction qui prend un objet <code>Server</code> en paramètre, il vaut mieux utiliser les tests ordinaires.</p>
<p>Il est tout à fait possible, et même agréable, de mettre quelques tests simples en doctests qui aident à la documentation, et de faire les tests les plus compliqués via <code>pytest</code>.</p>
<p>Prochaine étape, les mocks. Parti de là, je pourrai vous dire quelles parties de votre programme tester en priorité, et comment. Au début je voulais faire l&#8217;inverse, mais finalement, c&#8217;est plus pratique.</p>
<hr />
<p><a href="https://github.com/sametmax/codes-des-articles/blob/master/2014/decembre/docstests.py">Télécharger le code de l&#8217;article</a></p>


feed_id: http://sametmax.com/?p=12742
title: 0bin.net est de nouveau en ligne &#160; Recently updated !
uri: 0bin-net-est-de-nouveau-en-ligne
url: http://sametmax.com/0bin-net-est-de-nouveau-en-ligne/
content:
<p><a href="http://sametmax.com/0bin-sest-fait-tej/">0bin était down</a>, on a supprimé la page en cause, et on l&#8217;a remis up.</p>
<p>On ne sait pas trop comment lutter contre ça. Même TPB a dû avoir 40 noms de domaine pour s&#8217;en sortir, et franchement on n&#8217;a pas envie de se taper autant de boulot pour un projet qui ne nous rapporte rien.</p>
<p>Que faire donc ?</p>
<p>D&#8217;abord, créer une admin pour 0bin pour supprimer une page plus facilement. Ça nous évitera de dépasser les délais la prochaine fois, car je n&#8217;étais pas dispo et Max ne savait pas comment faire. C&#8217;est pas que c&#8217;est compliqué, mais ça prend du temps, faut lire la doc, se connecter au serveur, etc. Et forcément, c&#8217;est du temps qu&#8217;on préfère passer sur Dota ou des projets qui rapportent des sous.</p>
<p>Ensuite, prendre le temps de vous rappeler que <a href="http://0bin.net/">0bin.net</a> n&#8217;est qu&#8217;une instance de 0bin. Un exemple. Multiplier les instances est encore le meilleur moyen d&#8217;avoir l&#8217;outil à disposition. Et le process est <a href="https://0bin.readthedocs.org/en/latest/">plutôt bien documenté</a>.</p>
<p>Mais une fois qu&#8217;on a posté son truc sur une instance, si elle tombe, que fait-on ?</p>
<p>Pour le moment on est baisé. </p>
<p>On pourrait donc imaginer de rajouter une fonction de distribution à 0bin. L&#8217;idée serait de se lier via une API simple à d&#8217;autres 0bin en qui on a confiance. Si quelqu&#8217;un poste sur l&#8217;un, tous les autres reçoivent une copie. Ainsi dans le lot, il y en aura bien un qui résistera. </p>
<p>Je me tâte à faire ça dans la semaine. Déjà 0bin a besoin d&#8217;un portage qui supporte Python 3. Ensuite quelques tests unitaires ne feraient pas de mal. Une fois que c&#8217;est fait, je freeze cette version, et je lance 1bin.net, la version suivante. Avec du crossbar.io, du angularjs et du mode distribué. Le truc sera plus lourd, uniquement compatible 2.7 et plus compliqué, donc je préfère en faire une version à part. </p>
<p>Ça se tente, voir si j&#8217;arrive à débloquer un peu de temps pour le faire, mais c&#8217;est pas impossible. Stay tuned.</p>


feed_id: http://sametmax.com/?p=12766
uri: Quelle-est-la-différence-entre-bloquer-et-en-cours-d-exéc
url: http://sametmax.com/quelle-est-la-difference-entre-bloquer-et-en-cours-dexecution/
title:
Quelle est la différence entre &#8220;bloquer&#8221; et &#8220;en cours d&#8217;exécution&#8221; ? &#160; Recently updated !

content:
<p>On vous dit qu&#8217;il faut faire attention en utilisant des technologies non bloquantes, car si on bloque dans la boucle d&#8217;événement, on bloque tout le programme, et on perd l’intérêt de l&#8217;outil.</p>
<p>C&#8217;est vrai, mais que veut dire &#8220;bloquer&#8221; ?</p>
<p>Car si je fais :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">for</span> x <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">range</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">1000000</span><span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span>x<span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>Mon programme va tourner longtemps, et la boucle d’événement va bloquer, n&#8217;est-ce pas ?</p>
<p>En fait, &#8220;bloquer&#8221; est un abus de langage car il y a plusieurs raisons pour bloquer. Dans notre contexte, il faudrait dire &#8220;bloquer en attente d&#8217;une entrée ou d&#8217;une sortie&#8221;. D&#8217;où l&#8217;appellation &#8220;Aynschronous non blocking I/O&#8221; des technos types NodeJS, Twisted, Tornado, Gevent, etc.</p>
<p>En effet, il faut distinguer deux causes d&#8217;attente à votre programme :</p>
<ul>
<li>Attendre que vos instructions se terminent. C&#8217;est être &#8220;en cours d&#8217;exécution&#8221;.</li>
<li>Attendre qu&#8217;un événement extérieur (écrire sur le disque, lire une socket, un clic de souris) arrive à sa conclusion. C&#8217;est bloquer sur de l&#8217;I/O.</li>
</ul>
<p>Le premier cas est impossible à éviter. Tout au mieux pouvons-nous répartir la charge du programme sur plusieurs cœurs, processeurs voire machines. Le code devra toujours attendre qu&#8217;il se termine, mais ça ira plus vite.</p>
<p>Dans le contexte de la programmation non bloquante telle qu&#8217;on vous en a parlé, on est donc dans le deuxième cas.</p>
<p>Il ne s&#8217;agit alors pas de s&#8217;interdire de faire des boucles ou autre opération longue (ou plutôt, c&#8217;est un problème d&#8217;optimisation ordinaire qui n&#8217;a rien à voir avec le fait de bloquer), il s&#8217;agit de ne pas &#8220;attendre à ne rien faire&#8221; quand une opération extérieure est en cours.</p>
<p>C&#8217;est ce que font naturellement NodeJS, Twisted, Tornado, Gevent &amp; Co. Quand on fait un échange HTTP, le bout de données part, puis le reste du code continue de tourner, passant à la tâche suivante, en attendant que le paquet traverse le réseau, atteigne l&#8217;autre machine, qui vous répond finalement. C&#8217;est ce temps, incompressible, sans contrôle de votre côté, durant lequel il ne faut pas bloquer. Le gain de perf est que votre programme ne se la touche pas pendant les temps d&#8217;attente, mais bien entendu que VOTRE, lui, code va prendre du temps et &#8220;bloquer&#8221; le processeur. Il faut bien qu&#8217;il s&#8217;exécute.</p>
<p>Ce qu&#8217;on entend donc par &#8220;il ne faut pas faire d&#8217;opération bloquante dans un code qui est déjà non bloquant&#8221; c&#8217;est &#8220;il ne faut pas utiliser un outil à l&#8217;API bloquante au milieu d&#8217;autres outils non bloquants&#8221;.</p>
<p>Par exemple, n&#8217;utilisez pas <a href="http://docs.python-requests.org/en/latest/">requests</a> avec Twisted, car requests est codé pour attendre sans rien faire jusqu’à obtenir une réponse à chaque requête, bloquant Twisted. Utilisez plutôt <a href="http://treq.readthedocs.org/en/latest/">treq</a>. C&#8217;est pareil pour la lecture d&#8217;un fichier, une requête de base de données, etc. Et il existe des boucles d&#8217;événements ailleurs que sur le serveur : une page Web possède sa propre boucle (c&#8217;est pour cela que tout JS est asynchrone), un toolkit GUI comme QT ou GTK aussi (c&#8217;est pour ça qu&#8217;ils utilisent la programmation événementielle), etc.</p>
<p>Maintenant vous allez me dire : mais pourquoi bloquer alors ? Pourquoi ne pas toujours éviter de bloquer ?</p>
<p>Et bien parce que si on ne bloque pas, on ne peut pas écrire un programme ligne à ligne. On est obligé d&#8217;adopter un style de programmation asynchrone puisqu&#8217;on ne sait pas quand le résultat de certaines lignes va arriver. Ça veut dire des callbacks, ou des futures, ou des coroutines, ou du message passing&#8230; Bref, un truc plus compliqué. Or, on n&#8217;a pas forcément besoin de ce niveau de performance. En fait, la grande majorité des programmes n&#8217;ont pas besoin de ce niveau de performance. Donc, on bloque en attendant, non pas Godot, mais l&#8217;I/O, parce que c&#8217;est plus simple à écrire. Pour pas se faire chier.</p>
<p>Il y a bien des moyens de contourner ce problème : les threads, le multiprocessing, les coroutines, etc. Parfois même, on ignore le problème : bloquer quelques ms au milieu d&#8217;une boucle d’événements une fois par seconde n&#8217;est pas un drame. Une fois que j&#8217;ai fini le dossier sur les tests unitaires, je vous ferai un dossier sur la programmation non bloquante, avec aussi une esquisse de la parallélisation.</p>
<p>En attendant, ne stressez pas parce que votre code &#8220;bloque&#8221; parce qu&#8217;il travaille longtemps, assurez-vous juste que les APIs que vous utilisez ne bloquent pas pendant l&#8217;I/O, et vous êtes ok.</p>
<p>Et comment savoir ? Et bien si une donnée rentre ou sort de votre programme (ça ne fait pas partie du code source), c&#8217;est de l&#8217;I/O. Si votre code ressemble à ça :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;">res <span style="color: #66cc66;">=</span> faire_operation_sur_IO<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
faire_un_truc_avec_le_res<span style="color: black;">&#40;</span>res<span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>Alors votre outil est bloquant, puisque qu&#8217;il compte sur le fait que la deuxième ligne sera exécutée à coup sûr quand la première sera terminée. Un outil non bloquant exigera quelque chose pour gérer le retour du résultat plus tard: un callback, une promesse, un <code>yield</code>&#8230;</p>


feed_id: http://sametmax.com/?p=12815
title: Des bouts de Python cachés &#160; Recently updated !
uri: Des-bouts-de-Python-cachés-Recently-updated
url: http://sametmax.com/des-bouts-de-python-caches/
content:
<p>J&#8217;aime bien fouiner pour trouver des petits trucs insolites dans mes techos. Cet <a href="http://stackoverflow.com/questions/101268/hidden-features-of-python?page=3&#038;tab=oldest#tab-top">excellent post</a> sur SO est un bon début, mais on découvre toujours de nouvelles choses.</p>
<h2>ChainMap</h2>
<p>Vous vous souvenez de <a href="http://sametmax.com/chercher-dans-plusieurs-dicts-a-la-fois-avec-chainmap/">ChainMap</a> ? C&#8217;est top, mais uniquement en Python 3. </p>
<p>Et bien il existe une version cachée en Python 2 :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">from</span> <span style="color: #dc143c;">ConfigParser</span> <span style="color: #ff7700;font-weight:bold;">import</span> _Chainmap <span style="color: #ff7700;font-weight:bold;">as</span> ChainMap</pre></td></tr></table></div>

<p>C&#8217;est pas aussi complet (il n&#8217;y a pas les méthodes <code>new_child</code> et <code>parents</code>), mais ça peut servir.</p>
<p>Si néanmoins, vous avez besoin de l&#8217;implémentation complète, il existe <a href="https://github.com/justanr/Py2ChainMap">un backport</a> installable avec <a href="http://sametmax.com/votre-python-aime-les-pip/">pip</a> :</p>
<p><code lang="bash">pip install Py2ChainMap</code></p>
<h2>str.startswith, str.endswith et un tuple</h2>
<p>Pour beaucoup de situations, une regex en Python, c&#8217;est overkill. On a <code>in</code> pour vérifier qu&#8217;une chaîne en contient une autre. Et on a <code>str.startswith()</code> et <code>str.endswith()</code> pour vérifier qu&#8217;une chaîne commence ou finit par une autre. Avec des <code>strip()</code>/<code>split()</code>/<code>lower()</code>, on finit souvent par s&#8217;en sortir, et l&#8217;usage de toutes ces méthodes est en général plus performant que d&#8217;utiliser <code>re</code>.</p>
<p>Mais si vous avez plusieurs chaînes à vérifier ? Pas de problème, <code>str.startswith()</code> et <code>str.endswith()</code> acceptent aussi des tuples :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #483d8b;">&quot;Je suis une chaîne qui a du caractère&quot;</span>.<span style="color: black;">startswith</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'Tu'</span><span style="color: black;">&#41;</span>
<span style="color: #008000;">False</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #483d8b;">&quot;Je suis une chaîne qui a du caractère&quot;</span>.<span style="color: black;">startswith</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'Je'</span><span style="color: black;">&#41;</span>
<span style="color: #008000;">True</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #483d8b;">&quot;Je suis une chaîne qui a du caractère&quot;</span>.<span style="color: black;">startswith</span><span style="color: black;">&#40;</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'Tu'</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'Je'</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
<span style="color: #008000;">True</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span></pre></td></tr></table></div>

<h2>Les espaces entre une instance et son attribut sont ignorés</h2>
<p>Bien que la deuxième ligne soit très moche, elle est parfaitement valide :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #483d8b;">&quot;Yolo&quot;</span>.<span style="color: black;">upper</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
<span style="color: #483d8b;">'YOLO'</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #483d8b;">&quot;Yolo&quot;</span>           .<span style="color: black;">upper</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
<span style="color: #483d8b;">'YOLO'</span></pre></td></tr></table></div>

<p>Or on peut intercepter l&#8217;accès aux attributs à la volée en Python grâce aux <a href="http://sametmax.com/le-guide-ultime-et-definitif-sur-la-programmation-orientee-objet-en-python-a-lusage-des-debutants-qui-sont-rassures-par-les-textes-detailles-qui-prennent-le-temps-de-tout-expliquer-partie-6/">méthodes magiques</a>.</p>
<p>Ça veut dire qu&#8217;on peut implémenter des &#8220;symboles&#8221; en Python.</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">class</span> SymbolMaker<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
&nbsp;
    symbols <span style="color: #66cc66;">=</span> <span style="color: #008000;">set</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> <span style="color: #0000cd;">__getattr__</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: #66cc66;">,</span> value<span style="color: black;">&#41;</span>:
        symbols.<span style="color: black;">add</span><span style="color: black;">&#40;</span>value<span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #66cc66;">&gt;&gt;&gt;</span> make_symbol <span style="color: #66cc66;">=</span> SymbolMaker<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> make_symbol   .<span style="color: black;">start</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> make_symbol   .<span style="color: black;">end</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> SymbolMaker.<span style="color: black;">symbols</span>
<span style="color: black;">&#123;</span><span style="color: #483d8b;">'end'</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'start'</span><span style="color: black;">&#125;</span></pre></td></tr></table></div>

<p>Je n&#8217;ai pas dit qu&#8217;on devrait le faire, j&#8217;ai dit qu&#8217;on pouvait :) D&#8217;ailleurs, y en a qui <a href="http://entrian.com/goto/">l&#8217;utilisent pour implémenter <code>GOTO</code> en Python</a>. The troll is strong with this &#8220;feature&#8221;.</p>


feed_id: http://sametmax.com/?p=12693
title: Introduction au currying &#160; Recently updated !
uri: Introduction-au-currying
url: http://sametmax.com/introduction-au-currying/
content:
<p>Le currying (ou Curryfication pour les frencofans) est le nom donné à une technique de programmation qui consiste à créer une fonction à partir d&#8217;une autre fonction et d&#8217;une liste partielle de paramètres destinés à celle-ci. On retrouve massivement cette technique en programmation fonctionnelle puisqu&#8217;elle permet de créer une fonction pure à partir d&#8217;une autre fonction pure. C&#8217;est une forme de réutilisabilité de code.</p>
<p>La forme la plus simple de currying est de réécrire une fonction appelant l&#8217;autre. Par exemple, soit une fonction pour multiplier tous les éléments d&#8217;un itérable :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">def</span> multiply<span style="color: black;">&#40;</span>iterable<span style="color: #66cc66;">,</span> number<span style="color: black;">&#41;</span>:
    <span style="color: #483d8b;">&quot;&quot;&quot; Multiplie tous les éléments d'un itérable par un nombre.
&nbsp;
        Exemple :
&nbsp;
            &gt;&gt;&gt; list(multiply([1, 2, 3], 2))
            [2, 4, 6]
    &quot;&quot;&quot;</span>
    <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: black;">&#40;</span>x * number <span style="color: #ff7700;font-weight:bold;">for</span> x <span style="color: #ff7700;font-weight:bold;">in</span> iterable<span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>On peut ensuite créer une fonction qui multipliera par 2 tous les éléments d&#8217;un itérable :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">def</span> doubled<span style="color: black;">&#40;</span>iterable<span style="color: black;">&#41;</span>:
    <span style="color: #483d8b;">&quot;&quot;&quot; Multiplie tous les éléments d'un itérable par un 2.
&nbsp;
        Exemple :
&nbsp;
            &gt;&gt;&gt; list(doubled([1, 2, 3]))
            [2, 4, 6]
    &quot;&quot;&quot;</span>
    <span style="color: #ff7700;font-weight:bold;">return</span> multiply<span style="color: black;">&#40;</span>iterable<span style="color: #66cc66;">,</span> <span style="color: #ff4500;">2</span><span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>C&#8217;est une forme de currying. On créé une fonction qui fait ce que fait une autre fonction, mais avec des arguments par défaut.</p>
<p>Python possède une fonction pour faire ça automatiquement avec n&#8217;importe quelle fonction :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #ff7700;font-weight:bold;">from</span> functools <span style="color: #ff7700;font-weight:bold;">import</span> partial 
<span style="color: #66cc66;">&gt;&gt;&gt;</span> tripled <span style="color: #66cc66;">=</span> partial<span style="color: black;">&#40;</span>multiply<span style="color: #66cc66;">,</span> number<span style="color: #66cc66;">=</span><span style="color: #ff4500;">3</span><span style="color: black;">&#41;</span> <span style="color: #808080; font-style: italic;"># on curryfie ici</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #008000;">list</span><span style="color: black;">&#40;</span>tripled<span style="color: black;">&#40;</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">1</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">2</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">3</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span> <span style="color: #808080; font-style: italic;"># nouvelle fonction avec un seul argument</span>
<span style="color: black;">&#91;</span><span style="color: #ff4500;">3</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">6</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">9</span><span style="color: black;">&#93;</span></pre></td></tr></table></div>

<p>Cela marche car, je vous le rappelle, les fonctions sont des objets en Python. On peut mettre une fonction (je ne parle pas de son résultat) dans une variable, passer une fonction en paramètre ou retourner une fonction dans une autre fonction. <strong>Les fonctions sont manipulables</strong>.</p>
<p>Il n&#8217;est pas rare d&#8217;utiliser les fonctions anonymes comme outils curryfication. En Python, on ferait ça avec une <a href="http://sametmax.com/fonctions-anonymes-en-python-ou-lambda/">lambda</a> :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">&gt;&gt;&gt;</span> tripled <span style="color: #66cc66;">=</span> <span style="color: #ff7700;font-weight:bold;">lambda</span> x: multiple<span style="color: black;">&#40;</span>x<span style="color: #66cc66;">,</span> <span style="color: #ff4500;">3</span><span style="color: black;">&#41;</span> 
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #008000;">list</span><span style="color: black;">&#40;</span>tripled<span style="color: black;">&#40;</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">1</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">2</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">3</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
<span style="color: black;">&#91;</span><span style="color: #ff4500;">3</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">6</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">9</span><span style="color: black;">&#93;</span></pre></td></tr></table></div>

<p>Certains outils, comme <a href="http://buzzdecafe.github.io/code/2014/05/16/introducing-ramda/">Ramda</a> en Javascript, vont plus loin, et exposent des fonctions qui se curryfient automatiquement.</p>
<p>Pour ce faire, il faut inverser l&#8217;ordre qu&#8217;on mettrait intuitivement aux arguments dans la déclaration d&#8217;une fonction :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #808080; font-style: italic;"># au lieu de multiply(iterable, number), on a :</span>
<span style="color: #ff7700;font-weight:bold;">def</span> multiply<span style="color: black;">&#40;</span>number<span style="color: #66cc66;">,</span> iterable<span style="color: #66cc66;">=</span><span style="color: #008000;">None</span><span style="color: black;">&#41;</span>:
    <span style="color: #808080; font-style: italic;"># Si on a pas d'itérable passé, on curryfie</span>
    <span style="color: #ff7700;font-weight:bold;">if</span> iterable <span style="color: #ff7700;font-weight:bold;">is</span> <span style="color: #008000;">None</span>:
        <span style="color: #ff7700;font-weight:bold;">return</span> partial<span style="color: black;">&#40;</span>multiply<span style="color: #66cc66;">,</span> number<span style="color: #66cc66;">=</span>number<span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: black;">&#40;</span>x * number <span style="color: #ff7700;font-weight:bold;">for</span> x <span style="color: #ff7700;font-weight:bold;">in</span> iterable<span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>Ainsi :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #008000;">list</span><span style="color: black;">&#40;</span>multiply<span style="color: black;">&#40;</span><span style="color: #ff4500;">2</span><span style="color: #66cc66;">,</span> <span style="color: black;">&#91;</span><span style="color: #ff4500;">1</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">2</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">3</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span> <span style="color: #808080; font-style: italic;"># pas de currying</span>
<span style="color: black;">&#91;</span><span style="color: #ff4500;">2</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">4</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">6</span><span style="color: black;">&#93;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> quintuple <span style="color: #66cc66;">=</span> multiply<span style="color: black;">&#40;</span><span style="color: #ff4500;">5</span><span style="color: black;">&#41;</span> <span style="color: #808080; font-style: italic;"># currying automatique</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #008000;">list</span><span style="color: black;">&#40;</span>quintuple<span style="color: black;">&#40;</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">1</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">2</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">3</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
<span style="color: black;">&#91;</span><span style="color: #ff4500;">5</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">10</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">15</span><span style="color: black;">&#93;</span></pre></td></tr></table></div>

<p>L’intérêt de ce style, c&#8217;est qu&#8217;on peut composer des traitements à partir de plusieurs sous traitements, presque déclarativement :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">def</span> remove<span style="color: black;">&#40;</span><span style="color: #008000;">filter</span><span style="color: #66cc66;">,</span> iterable<span style="color: #66cc66;">=</span><span style="color: #008000;">None</span><span style="color: black;">&#41;</span>:
    <span style="color: #483d8b;">&quot;&quot;&quot; Retire tous les éléments d'un itérable correspondant au filtre.
&nbsp;
        Exemple :
&nbsp;
            &gt;&gt;&gt; list(remove(lambda x: x &gt;= 4, [1, 2, 3, 4, 5]))
            [1, 2, 3]
    &quot;&quot;&quot;</span>
    <span style="color: #ff7700;font-weight:bold;">if</span> iterable <span style="color: #ff7700;font-weight:bold;">is</span> <span style="color: #008000;">None</span>:
        <span style="color: #ff7700;font-weight:bold;">return</span> partial<span style="color: black;">&#40;</span>remove<span style="color: #66cc66;">,</span> <span style="color: #008000;">filter</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: black;">&#40;</span>x <span style="color: #ff7700;font-weight:bold;">for</span> x <span style="color: #ff7700;font-weight:bold;">in</span> iterable <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #ff7700;font-weight:bold;">not</span> <span style="color: #008000;">filter</span><span style="color: black;">&#40;</span>x<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #66cc66;">&gt;&gt;&gt;</span> smalls <span style="color: #66cc66;">=</span> remove<span style="color: black;">&#40;</span><span style="color: #ff7700;font-weight:bold;">lambda</span> x: x <span style="color: #66cc66;">&gt;=</span> <span style="color: #ff4500;">4</span><span style="color: black;">&#41;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #008000;">list</span><span style="color: black;">&#40;</span>smalls<span style="color: black;">&#40;</span>tripled<span style="color: black;">&#40;</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">1</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">2</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">3</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">4</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span> <span style="color: #808080; font-style: italic;"># le traitement est auto descriptif</span>
<span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">3</span><span style="color: black;">&#93;</span></pre></td></tr></table></div>

<p>Néanmoins, il faut savoir que ce style n&#8217;est pas pythonique. En effet, en Python on préférera généralement utiliser des suites suite de générateurs. Soit par <a href="http://sametmax.com/python-love-les-listes-en-intention-partie-2/">intention</a>, soit via <a href="http://sametmax.com/comment-utiliser-yield-et-les-generateurs-en-python/">yield</a>.</p>
<p>Notre exemple serait alors :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">&gt;&gt;&gt;</span> tripled <span style="color: #66cc66;">=</span> <span style="color: black;">&#40;</span>x * <span style="color: #ff4500;">3</span> <span style="color: #ff7700;font-weight:bold;">for</span> x <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">1</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">2</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">3</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">4</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> smalls <span style="color: #66cc66;">=</span> <span style="color: black;">&#40;</span>x <span style="color: #ff7700;font-weight:bold;">for</span> x <span style="color: #ff7700;font-weight:bold;">in</span> tripled <span style="color: #ff7700;font-weight:bold;">if</span> x <span style="color: #66cc66;">&lt;=</span> <span style="color: #ff4500;">4</span><span style="color: black;">&#41;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #008000;">list</span><span style="color: black;">&#40;</span>smalls<span style="color: black;">&#41;</span>
<span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">3</span><span style="color: black;">&#93;</span></pre></td></tr></table></div>

<p>De plus, cette technique suppose qu&#8217;on ne profitera pas de certaines fonctionnalités, comme les paramètres par défaut des fonctions Python.</p>
<p>C&#8217;est toutefois une bonne chose à connaître. C&#8217;est occasionnellement utile en Python et peut produire des solutions très élégantes. C&#8217;est également une bonne chose à comprendre pour aborder d&#8217;autres langages plus fonctionnels qui les utilisent bien plus comme le Javascript, le Lisp, ou carrément le Haskell.</p>


feed_id: http://sametmax.com/?p=12854
title: Qu&#8217;est-ce qu&#8217;une coroutine en Python, et à quoi ça sert ?
uri: Qu-est-ce-qu-une-coroutine-en-Python-et-à-quoi-ça-sert
url: http://sametmax.com/quest-ce-quune-coroutine-en-python-et-a-quoi-ca-sert/
content:
<p>Si vous avez aimé les générateurs, vous avez du creuser un peu <code>yield</code> et vous apercevoir qu&#8217;on pouvait créer des coroutines avec. Mais sans vraiment comprendre ce que ça faisait.</p>
<p>On va se faire une petit intro. C&#8217;est un sujet vraiment avancé, donc si vous avez autre chose de moins compliqué à comprendre en Python (n&#8217;importe quoi à part les métaclasses :)), ne vous prenez pas la tête sur cet article. Ecoutez juste la musique :</p>
<p><span class='embed-youtube' style='text-align:center; display: block;'><iframe class='youtube-player' type='text/html' width='1170' height='689' src='http://www.youtube.com/embed/zqKZ_WIK5ms?version=3&#038;rel=1&#038;fs=1&#038;showsearch=0&#038;showinfo=1&#038;iv_load_policy=1&#038;wmode=transparent' frameborder='0' allowfullscreen='true'></iframe></span></p>
<p>D&#8217;abord, rappel sur le fonctionnement des générateurs (qui sont un prérequis de l&#8217;article, donc si besoin, relisez le <a href="http://sametmax.com/comment-utiliser-yield-et-les-generateurs-en-python/">tuto dédié</a>) :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">def</span> soleil<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'Premier next()'</span><span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'Yield 1'</span><span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">yield</span> <span style="color: #ff4500;">1</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'Deuxième next()'</span><span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'Yield 2'</span><span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">yield</span> <span style="color: #ff4500;">2</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'Troisième next()'</span><span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'Yield 3'</span><span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">yield</span> <span style="color: #ff4500;">3</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># pas de quatrième next(),</span>
    <span style="color: #808080; font-style: italic;"># donc on ne passe jamais ici</span>
    <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'Pas vu'</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># rappel, ceci ne déclenche pas le code </span>
<span style="color: #808080; font-style: italic;"># de soleil() puisqu'il y a yield dedans</span>
<span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;Creation du generateur&quot;</span><span style="color: black;">&#41;</span>
undeuxtrois <span style="color: #66cc66;">=</span> soleil<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># On execute le code jusqu'au yield 1</span>
res <span style="color: #66cc66;">=</span> next<span style="color: black;">&#40;</span>undeuxtrois<span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'res = %s'</span> % res<span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># On execute le code jusqu'au yield 2</span>
res <span style="color: #66cc66;">=</span> next<span style="color: black;">&#40;</span>undeuxtrois<span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'res = %s'</span> % res<span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># On execute le code jusqu'au yield 3</span>
res <span style="color: #66cc66;">=</span> next<span style="color: black;">&#40;</span>undeuxtrois<span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'res = %s'</span> % res<span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'Good bye'</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #808080; font-style: italic;">## Premier next()</span>
<span style="color: #808080; font-style: italic;">## Yield 1</span>
<span style="color: #808080; font-style: italic;">## res = 1</span>
<span style="color: #808080; font-style: italic;">## Deuxième next()</span>
<span style="color: #808080; font-style: italic;">## Yield 2</span>
<span style="color: #808080; font-style: italic;">## res = 2</span>
<span style="color: #808080; font-style: italic;">## Troisième next()</span>
<span style="color: #808080; font-style: italic;">## Yield 3</span>
<span style="color: #808080; font-style: italic;">## res = 3</span>
<span style="color: #808080; font-style: italic;">## Good bye</span></pre></td></tr></table></div>

<p>Chaque fois qu&#8217;on appelle <code>next()</code> sur le générateur, il va exécuter le code jusqu&#8217;au prochain <code>yield</code>, et retourner la valeur de celui-ci, puis mettre le générateur en pause.</p>
<p>On peut assigner le résultat d&#8217;un <code>yield</code>, mais si on fait des <code>next()</code>, on obtient toujours <code>None</code> :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">def</span> lune<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'Premier next()'</span><span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'Yield 1'</span><span style="color: black;">&#41;</span>
    x <span style="color: #66cc66;">=</span> <span style="color: black;">&#40;</span><span style="color: #ff7700;font-weight:bold;">yield</span> <span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'Deuxième next()'</span><span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'Avant le yield 2, x = %s'</span> % x<span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'Yield 2'</span><span style="color: black;">&#41;</span>
    x <span style="color: #66cc66;">=</span> <span style="color: black;">&#40;</span><span style="color: #ff7700;font-weight:bold;">yield</span> <span style="color: #ff4500;">2</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'Troisième next()'</span><span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'Avant le yield 3, x = %s'</span> % x<span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'Yield 3'</span><span style="color: black;">&#41;</span>
    x <span style="color: #66cc66;">=</span> <span style="color: black;">&#40;</span><span style="color: #ff7700;font-weight:bold;">yield</span> <span style="color: #ff4500;">3</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'Pas vu'</span><span style="color: black;">&#41;</span>
&nbsp;
&nbsp;
<span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;Creation du generateur&quot;</span><span style="color: black;">&#41;</span>
generateur <span style="color: #66cc66;">=</span> lune<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
res <span style="color: #66cc66;">=</span> next<span style="color: black;">&#40;</span>generateur<span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'res = %s'</span> % res<span style="color: black;">&#41;</span>
&nbsp;
res <span style="color: #66cc66;">=</span> next<span style="color: black;">&#40;</span>generateur<span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'res = %s'</span> % res<span style="color: black;">&#41;</span>
&nbsp;
res <span style="color: #66cc66;">=</span> next<span style="color: black;">&#40;</span>generateur<span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'res = %s'</span> % res<span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'Good bye'</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #808080; font-style: italic;">## Creation du generateur</span>
<span style="color: #808080; font-style: italic;">## Premier next()</span>
<span style="color: #808080; font-style: italic;">## Yield 1</span>
<span style="color: #808080; font-style: italic;">## res = 1</span>
<span style="color: #808080; font-style: italic;">## Deuxième next()</span>
<span style="color: #808080; font-style: italic;">## Avant le yield 2, x = None</span>
<span style="color: #808080; font-style: italic;">## Yield 2</span>
<span style="color: #808080; font-style: italic;">## res = 2</span>
<span style="color: #808080; font-style: italic;">## Troisième next()</span>
<span style="color: #808080; font-style: italic;">## Avant le yield 3, x = None</span>
<span style="color: #808080; font-style: italic;">## Yield 3</span>
<span style="color: #808080; font-style: italic;">## res = 3</span>
<span style="color: #808080; font-style: italic;">## Good bye</span></pre></td></tr></table></div>

<p>La raison est que cette valeur doit venir de l&#8217;extérieur. Pour la fournir, il faut utiliser la méthode <code>send()</code> et non la fonction <code>next()</code>.</p>
<p>Mais elle ne fonctionne pas du tout pareil. En fait, si on l&#8217;appelle cash pistache, ça plante :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;Creation du generateur&quot;</span><span style="color: black;">&#41;</span>
generateur <span style="color: #66cc66;">=</span> lune<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
res <span style="color: #66cc66;">=</span> generateur.<span style="color: black;">send</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;A&quot;</span><span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'res = %s'</span> % res<span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #808080; font-style: italic;">## Creation du generateur</span>
<span style="color: #808080; font-style: italic;">## Traceback (most recent call last):</span>
<span style="color: #808080; font-style: italic;">## File &quot;test.py&quot;, line 24, in </span>
<span style="color: #808080; font-style: italic;">##   res = generateur.send(&quot;A&quot;)</span>
<span style="color: #808080; font-style: italic;">##     TypeError: can't send non-None value to a just-started generator</span></pre></td></tr></table></div>

<p>C&#8217;est parce que, contrairement à <code>next()</code> qui va jusqu&#8217;au prochain <code>yield</code>, <code>send()</code> PART du dernier <code>yield</code> atteint pour aller au suivant.</p>
<p>Il faut donc d&#8217;abord arriver à un premier <code>yield</code> avant de faire un <code>send()</code>. On peut le faire en utilisant au moins un <code>next()</code>.</p>
<p>Voici donc notre nouveau code :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">def</span> lune<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'On fait au moins un next()'</span><span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'Yield 1'</span><span style="color: black;">&#41;</span>
&nbsp;
    x <span style="color: #66cc66;">=</span> <span style="color: black;">&#40;</span><span style="color: #ff7700;font-weight:bold;">yield</span> <span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'Premier send(), x = %s'</span> % x<span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'Yield 2'</span><span style="color: black;">&#41;</span>
&nbsp;
    x <span style="color: #66cc66;">=</span> <span style="color: black;">&#40;</span><span style="color: #ff7700;font-weight:bold;">yield</span> <span style="color: #ff4500;">2</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'Deuxième send(), x = %s'</span> % x<span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'Yield 3'</span><span style="color: black;">&#41;</span>
&nbsp;
    x <span style="color: #66cc66;">=</span> <span style="color: black;">&#40;</span><span style="color: #ff7700;font-weight:bold;">yield</span> <span style="color: #ff4500;">3</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># Comme on fait un next() et 3 send()</span>
    <span style="color: #808080; font-style: italic;"># on arrive là</span>
    <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'Troisième send(), x = %s'</span> % x<span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'YOLOOOOO'</span><span style="color: black;">&#41;</span>
&nbsp;
&nbsp;
<span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;Creation du generateur&quot;</span><span style="color: black;">&#41;</span>
generateur <span style="color: #66cc66;">=</span> lune<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
next<span style="color: black;">&#40;</span>generateur<span style="color: black;">&#41;</span> <span style="color: #808080; font-style: italic;"># Ou generateur.send(None)</span>
&nbsp;
res <span style="color: #66cc66;">=</span> generateur.<span style="color: black;">send</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;A&quot;</span><span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'res = %s'</span> % res<span style="color: black;">&#41;</span>
&nbsp;
res <span style="color: #66cc66;">=</span> generateur.<span style="color: black;">send</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;B&quot;</span><span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'res = %s'</span> % res<span style="color: black;">&#41;</span>
&nbsp;
res <span style="color: #66cc66;">=</span> generateur.<span style="color: black;">send</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;C&quot;</span><span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'res = %s'</span> % res<span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'Good bye'</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #808080; font-style: italic;">## Creation du generateur</span>
<span style="color: #808080; font-style: italic;">## On fait au moins un next()</span>
<span style="color: #808080; font-style: italic;">## Yield 1</span>
<span style="color: #808080; font-style: italic;">## Premier send(), x = A</span>
<span style="color: #808080; font-style: italic;">## Yield 2</span>
<span style="color: #808080; font-style: italic;">## res = 2</span>
<span style="color: #808080; font-style: italic;">## Deuxième send(), x = B</span>
<span style="color: #808080; font-style: italic;">## Yield 3</span>
<span style="color: #808080; font-style: italic;">## res = 3</span>
<span style="color: #808080; font-style: italic;">## Troisième send(), x = C</span>
<span style="color: #808080; font-style: italic;">## YOLOOOOO</span>
<span style="color: #808080; font-style: italic;">## Traceback (most recent call last):</span>
<span style="color: #808080; font-style: italic;">##   File &quot;test.py&quot;, line 33, in </span>
<span style="color: #808080; font-style: italic;">##     res = generateur.send(&quot;C&quot;)</span>
<span style="color: #808080; font-style: italic;">## StopIteration</span></pre></td></tr></table></div>

<p><code>send()</code> agit donc comme <code>next()</code>. Il va aller jusqu&#8217;au prochain <code>yield</code> et lui faire retourner sa valeur. Mais il y a des différences :</p>
<ul>
<li>Elle doit partir d&#8217;un précédent <code>yield</code>.</li>
<li>Donc il faut au moins avoir atteint un <code>yield</code> via <code>next()</code>.</li>
<li>Ce précédent <code>yield</code> peut retourner une valeur : celle passée via <code>send(val).</code></li>
</ul>
<p>La valeur peut être n&#8217;importe quel objet : string, int, classe, list, etc.</p>
<p>Bref, <code>send()</code> permet de créer un générateur donc le comportement n&#8217;est pas figé dans le marbre.</p>
<p>Par exemple :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">def</span> creer_fontaine<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    contenu <span style="color: #66cc66;">=</span> <span style="color: #483d8b;">&quot;soda&quot;</span> 
    <span style="color: #ff7700;font-weight:bold;">while</span> <span style="color: #008000;">True</span>:
        x <span style="color: #66cc66;">=</span> <span style="color: #ff7700;font-weight:bold;">yield</span> contenu
        <span style="color: #ff7700;font-weight:bold;">if</span> x:
            contenu <span style="color: #66cc66;">=</span> x
&nbsp;
&nbsp;
fontaine <span style="color: #66cc66;">=</span> creer_fontaine<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">for</span> x <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">range</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">5</span><span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span>next<span style="color: black;">&#40;</span>fontaine<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># on change le contenu de la fontaine</span>
fontaine.<span style="color: black;">send</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;lait&quot;</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">for</span> x <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">range</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">5</span><span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span>next<span style="color: black;">&#40;</span>fontaine<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
&nbsp;
soda
soda
soda
soda
soda
lait
lait
lait
lait
lait</pre></td></tr></table></div>

<p>On peut même s&#8217;en servir pour faire des trucs chelou comme injecter une dépendance à la volée ou contrôler le flux de son générateur :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">def</span> fuckitjaiplusdenomcool<span style="color: black;">&#40;</span>start<span style="color: #66cc66;">,</span> inc<span style="color: #66cc66;">=</span><span style="color: #ff7700;font-weight:bold;">lambda</span> x: x + <span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span>:
    x <span style="color: #66cc66;">=</span> start
    <span style="color: #808080; font-style: italic;"># on controle le flux du générateur en changeant</span>
    <span style="color: #808080; font-style: italic;"># la valeur de x qui peut tout stopper</span>
    <span style="color: #ff7700;font-weight:bold;">while</span> x:
        sent <span style="color: #66cc66;">=</span> <span style="color: #ff7700;font-weight:bold;">yield</span> x
        <span style="color: #ff7700;font-weight:bold;">if</span> sent:
            inc <span style="color: #66cc66;">=</span> sent
        <span style="color: #808080; font-style: italic;"># la valeur de x dépend de ce bout de code</span>
        <span style="color: #808080; font-style: italic;"># qui est injectable</span>
        x <span style="color: #66cc66;">=</span> inc<span style="color: black;">&#40;</span>x<span style="color: black;">&#41;</span>
&nbsp;
&nbsp;
generateur <span style="color: #66cc66;">=</span> fuckitjaiplusdenomcool<span style="color: black;">&#40;</span><span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">for</span> x <span style="color: #ff7700;font-weight:bold;">in</span> generateur:
    <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span>x<span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">if</span> x &amp;gt<span style="color: #66cc66;">;</span> <span style="color: #ff4500;">10</span>:
        <span style="color: #808080; font-style: italic;"># si on dépasse 10, on décrémente</span>
        generateur.<span style="color: black;">send</span><span style="color: black;">&#40;</span><span style="color: #ff7700;font-weight:bold;">lambda</span> x: x - <span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #808080; font-style: italic;">## 1</span>
<span style="color: #808080; font-style: italic;">## 2</span>
<span style="color: #808080; font-style: italic;">## 3</span>
<span style="color: #808080; font-style: italic;">## 4</span>
<span style="color: #808080; font-style: italic;">## 5</span>
<span style="color: #808080; font-style: italic;">## 6</span>
<span style="color: #808080; font-style: italic;">## 7</span>
<span style="color: #808080; font-style: italic;">## 8</span>
<span style="color: #808080; font-style: italic;">## 9</span>
<span style="color: #808080; font-style: italic;">## 10</span>
<span style="color: #808080; font-style: italic;">## 11</span>
<span style="color: #808080; font-style: italic;">## 9</span>
<span style="color: #808080; font-style: italic;">## 8</span>
<span style="color: #808080; font-style: italic;">## 7</span>
<span style="color: #808080; font-style: italic;">## 6</span>
<span style="color: #808080; font-style: italic;">## 5</span>
<span style="color: #808080; font-style: italic;">## 4</span>
<span style="color: #808080; font-style: italic;">## 3</span>
<span style="color: #808080; font-style: italic;">## 2</span>
<span style="color: #808080; font-style: italic;">## 1</span></pre></td></tr></table></div>

<p>Mais bon, pas la peine de rentrer dans des cas si compliqués.</p>
<p>Néanmoins, un cas d&#8217;usage de <code>send()</code> est de créer une coroutine. Une coroutine est simplement une tâche.</p>
<p>C&#8217;est un bout de code qui fait une tache, avec un bout d&#8217;initialisation, et un bout de finalisation, et un bout d&#8217;exécution.</p>
<p>Par exemple, j&#8217;ai un filtre qui prend un fichier rempli d&#8217;adresses IP. Il va recevoir du texte, et si le texte contient une adresse IP, il le signale, et remplit un compteur sur le disque.</p>
<p>Si on devait coder ça en objet on dirait :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">re</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">class</span> Filtre:
&nbsp;
    <span style="color: #808080; font-style: italic;"># initialisation</span>
    <span style="color: #ff7700;font-weight:bold;">def</span> <span style="color: #0000cd;">__init__</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: #66cc66;">,</span> ipfile<span style="color: #66cc66;">,</span> counterfile<span style="color: black;">&#41;</span>:
&nbsp;
        <span style="color: #ff7700;font-weight:bold;">with</span> <span style="color: #008000;">open</span><span style="color: black;">&#40;</span>ipfile<span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'r'</span><span style="color: black;">&#41;</span> <span style="color: #ff7700;font-weight:bold;">as</span> f:
            <span style="color: #008000;">self</span>.<span style="color: black;">banned_ips</span> <span style="color: #66cc66;">=</span> <span style="color: #008000;">set</span><span style="color: black;">&#40;</span>f<span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">with</span> <span style="color: #008000;">open</span><span style="color: black;">&#40;</span>counterfile<span style="color: black;">&#41;</span> <span style="color: #ff7700;font-weight:bold;">as</span> f:
            <span style="color: #008000;">self</span>.<span style="color: black;">count</span> <span style="color: #66cc66;">=</span> <span style="color: #008000;">int</span><span style="color: black;">&#40;</span>f.<span style="color: black;">read</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">counterfile</span> <span style="color: #66cc66;">=</span> <span style="color: #008000;">open</span><span style="color: black;">&#40;</span>counterfile<span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'w'</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> check<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: #66cc66;">,</span> line<span style="color: black;">&#41;</span>:
        <span style="color: #808080; font-style: italic;"># récupère les ip et check celles qui sont </span>
        <span style="color: #808080; font-style: italic;"># à filtrer</span>
        ips <span style="color: #66cc66;">=</span> <span style="color: #dc143c;">re</span>.<span style="color: black;">findall</span><span style="color: black;">&#40;</span> r<span style="color: #483d8b;">'[0-9]+(?:<span style="color: #000099; font-weight: bold;">\.</span>[0-9]+){3}'</span><span style="color: #66cc66;">,</span> line<span style="color: black;">&#41;</span>
        bad_ips <span style="color: #66cc66;">=</span> <span style="color: black;">&#91;</span>ip <span style="color: #ff7700;font-weight:bold;">for</span> ip <span style="color: #ff7700;font-weight:bold;">in</span> ips <span style="color: #ff7700;font-weight:bold;">if</span> ip <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">self</span>.<span style="color: black;">banned_ips</span><span style="color: black;">&#93;</span>
&nbsp;
        <span style="color: #808080; font-style: italic;"># si il y a des ip à filtrer, on incrémente le compteur</span>
        <span style="color: #ff7700;font-weight:bold;">if</span> bad_ips:
            <span style="color: #008000;">self</span>.<span style="color: black;">count</span> +<span style="color: #66cc66;">=</span> <span style="color: #008000;">len</span><span style="color: black;">&#40;</span>bad_ips<span style="color: black;">&#41;</span>
            <span style="color: #008000;">self</span>.<span style="color: black;">counterfile</span>.<span style="color: black;">seek</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#41;</span>
            <span style="color: #008000;">self</span>.<span style="color: black;">counterfile</span>.<span style="color: black;">write</span><span style="color: black;">&#40;</span><span style="color: #008000;">str</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>.<span style="color: black;">count</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
&nbsp;
        <span style="color: #808080; font-style: italic;"># on retourn les valeurs trouvées</span>
        <span style="color: #ff7700;font-weight:bold;">return</span> bad_ips
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> close<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
        <span style="color: #008000;">self</span>.<span style="color: black;">counterfile</span>.<span style="color: black;">close</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>On l&#8217;utiliserait comme ça :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;">f <span style="color: #66cc66;">=</span> Filtre<span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;/chemin/vers/liste&quot;</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">&quot;/chemin/vers/counteur&quot;</span><span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">for</span> line <span style="color: #ff7700;font-weight:bold;">in</span> text:
    <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span>f.<span style="color: black;">check</span><span style="color: black;">&#40;</span>line<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
f.<span style="color: black;">close</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>Notez que pour une tâche, l&#8217;API est toujours la même : initialiser, exécuter la tâche autant de fois que nécessaire, puis finaliser.</p>
<p>Les coroutines sont un mot qu&#8217;on met sur ce principe (initialiser, exec, finaliser), mais avec une API sous forme de générateur. Le même code en coroutine :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">def</span> filtre<span style="color: black;">&#40;</span>ipfile<span style="color: #66cc66;">,</span> counterfile<span style="color: black;">&#41;</span>:
&nbsp;
    <span style="color: #808080; font-style: italic;"># Initialisation</span>
    <span style="color: #ff7700;font-weight:bold;">with</span> <span style="color: #008000;">open</span><span style="color: black;">&#40;</span>ipfile<span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'r'</span><span style="color: black;">&#41;</span> <span style="color: #ff7700;font-weight:bold;">as</span> f:
        banned_ips <span style="color: #66cc66;">=</span> <span style="color: #008000;">set</span><span style="color: black;">&#40;</span>f<span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">with</span> <span style="color: #008000;">open</span><span style="color: black;">&#40;</span>counterfile<span style="color: black;">&#41;</span> <span style="color: #ff7700;font-weight:bold;">as</span> f:
        count <span style="color: #66cc66;">=</span> <span style="color: #008000;">int</span><span style="color: black;">&#40;</span>f.<span style="color: black;">read</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
    counterfile <span style="color: #66cc66;">=</span> <span style="color: #008000;">open</span><span style="color: black;">&#40;</span>counterfile<span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'w'</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># Exécution</span>
    bad_ips <span style="color: #66cc66;">=</span> <span style="color: black;">&#91;</span><span style="color: black;">&#93;</span>
    <span style="color: #ff7700;font-weight:bold;">while</span> <span style="color: #008000;">True</span>:
&nbsp;
        <span style="color: #ff7700;font-weight:bold;">try</span>:
            <span style="color: #808080; font-style: italic;"># entree et sortie de notre send(), qui équivaut</span>
            <span style="color: #808080; font-style: italic;"># aux params de &quot;check()&quot;</span>
            line <span style="color: #66cc66;">=</span> <span style="color: #ff7700;font-weight:bold;">yield</span> bad_ips
&nbsp;
        <span style="color: #808080; font-style: italic;"># GeneratorExit est levé is on fait generator.close()</span>
        <span style="color: #808080; font-style: italic;"># On ne peut pas ignorer cette erreur, mais</span>
        <span style="color: #808080; font-style: italic;"># on peut mettre du code de finalisation ici.</span>
        <span style="color: #808080; font-style: italic;"># Bon en vrai faudrait faire un finally quelque part</span>
        <span style="color: #808080; font-style: italic;"># mais c'est pour l'exemple bande de peer reviewers</span>
        <span style="color: #ff7700;font-weight:bold;">except</span> GeneratorExit:
                <span style="color: #008000;">self</span>.<span style="color: black;">counterfile</span>.<span style="color: black;">close</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
        ips <span style="color: #66cc66;">=</span> <span style="color: #dc143c;">re</span>.<span style="color: black;">findall</span><span style="color: black;">&#40;</span> r<span style="color: #483d8b;">'[0-9]+(?:<span style="color: #000099; font-weight: bold;">\.</span>[0-9]+){3}'</span><span style="color: #66cc66;">,</span> line<span style="color: black;">&#41;</span>
        bad_ips <span style="color: #66cc66;">=</span> <span style="color: black;">&#91;</span>ip <span style="color: #ff7700;font-weight:bold;">for</span> ip <span style="color: #ff7700;font-weight:bold;">in</span> ips <span style="color: #ff7700;font-weight:bold;">if</span> ip <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">self</span>.<span style="color: black;">banned_ips</span><span style="color: black;">&#93;</span>
&nbsp;
        <span style="color: #808080; font-style: italic;"># si il y a des ip à filtrer, on incrémente le compteur</span>
        <span style="color: #ff7700;font-weight:bold;">if</span> bad_ips:
            <span style="color: #008000;">self</span>.<span style="color: black;">count</span> +<span style="color: #66cc66;">=</span> <span style="color: #008000;">len</span><span style="color: black;">&#40;</span>bad_ips<span style="color: black;">&#41;</span>
            <span style="color: #008000;">self</span>.<span style="color: black;">counterfile</span>.<span style="color: black;">seek</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#41;</span>
            <span style="color: #008000;">self</span>.<span style="color: black;">counterfile</span>.<span style="color: black;">write</span><span style="color: black;">&#40;</span><span style="color: #008000;">str</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>.<span style="color: black;">count</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>On l&#8217;utiliserait comme ça :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;">f <span style="color: #66cc66;">=</span> filtre<span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;/chemin/vers/liste&quot;</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">&quot;/chemin/vers/counteur&quot;</span><span style="color: black;">&#41;</span>
next<span style="color: black;">&#40;</span>f<span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">for</span> line <span style="color: #ff7700;font-weight:bold;">in</span> text:
    <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span>f.<span style="color: black;">send</span><span style="color: black;">&#40;</span>line<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
<span style="color: #808080; font-style: italic;"># ceci raise GeneratorExit</span>
f.<span style="color: black;">close</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>Généralement on veut pas se faire chier à appeler <code>next()</code> à chaque fois, donc toutes les libs à base de coroutine ont ce genre de décorateur :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">def</span> coroutine<span style="color: black;">&#40;</span>func<span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">def</span> wrapper<span style="color: black;">&#40;</span>*arg<span style="color: #66cc66;">,</span> **kwargs<span style="color: black;">&#41;</span>:
        generator <span style="color: #66cc66;">=</span> func<span style="color: black;">&#40;</span>*arg<span style="color: #66cc66;">,</span> **kwargs<span style="color: black;">&#41;</span>
        next<span style="color: black;">&#40;</span>generator<span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">return</span> generator
    <span style="color: #ff7700;font-weight:bold;">return</span> wrapper</pre></td></tr></table></div>

<p>Afin de pouvoir faire ça :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">@</span>coroutine
<span style="color: #ff7700;font-weight:bold;">def</span> filtre<span style="color: black;">&#40;</span>ipfile<span style="color: #66cc66;">,</span> counterfile<span style="color: black;">&#41;</span>:
    ...</pre></td></tr></table></div>

<p>Ca a un double usage : ça appelle <code>next()</code> automatiquement, et ça signale que la fonction est destinée à être utilisée comme coroutine.</p>
<p>Mais voilà, c&#8217;est tout, une coroutine c&#8217;est juste ça : utiliser un générateur pour faire une tâche qui consiste à s&#8217;initialiser, faire un traitement plusieurs fois, et optionellement, se finaliser. On utilisera une coroutine pour ne pas reinventer la roue car c&#8217;est un problème bien défini, qui a une solution. D&#8217;autant qu&#8217;une coroutine bouffe moins de ressources qu&#8217;une classe.</p>
<p>Les usages avancés des coroutines impliquent de chaîner plusieurs coroutines, comme des tuyaux.</p>
<p>Souvenez-vous, en Python il est courant de chaîner des générateurs :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">def</span> mettre_au_carre<span style="color: black;">&#40;</span>iterable<span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">for</span> x <span style="color: #ff7700;font-weight:bold;">in</span> iterable:
        <span style="color: #ff7700;font-weight:bold;">yield</span> x * x
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> filtrer_les_pairs<span style="color: black;">&#40;</span>iterable<span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">for</span> x <span style="color: #ff7700;font-weight:bold;">in</span> iterable:
        <span style="color: #ff7700;font-weight:bold;">if</span> x % <span style="color: #ff4500;">2</span> <span style="color: #66cc66;">==</span> <span style="color: #ff4500;">0</span>:
            <span style="color: #ff7700;font-weight:bold;">yield</span> x
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> strigifier<span style="color: black;">&#40;</span>iterable<span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">for</span> x <span style="color: #ff7700;font-weight:bold;">in</span> iterable:
        <span style="color: #ff7700;font-weight:bold;">yield</span> <span style="color: #008000;">str</span><span style="color: black;">&#40;</span>x<span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># on pipe les données d'un générateur à l'autre</span>
nombres <span style="color: #66cc66;">=</span> <span style="color: #008000;">range</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">10</span><span style="color: black;">&#41;</span>
carres <span style="color: #66cc66;">=</span> mettre_au_carre<span style="color: black;">&#40;</span>nombres<span style="color: black;">&#41;</span>
carres_pairs <span style="color: #66cc66;">=</span> filtrer_les_pairs<span style="color: black;">&#40;</span>carres<span style="color: black;">&#41;</span>
fete_du_string <span style="color: #66cc66;">=</span> strigifier<span style="color: black;">&#40;</span>carres_pairs<span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">for</span> x <span style="color: #ff7700;font-weight:bold;">in</span> fete_du_string:
    <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span><span style="color: #dc143c;">repr</span><span style="color: black;">&#40;</span>x<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #808080; font-style: italic;">## '0'</span>
<span style="color: #808080; font-style: italic;">## '4'</span>
<span style="color: #808080; font-style: italic;">## '16'</span>
<span style="color: #808080; font-style: italic;">## '36'</span>
<span style="color: #808080; font-style: italic;">## '64'</span></pre></td></tr></table></div>

<p>On peut faire pareil avec les coroutines. Cependant, la logique est inversée : au lieu de lire les données, on les envoie :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">@</span>coroutine
<span style="color: #ff7700;font-weight:bold;">def</span> mettre_au_carre<span style="color: black;">&#40;</span>ouput<span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">while</span> <span style="color: #008000;">True</span>:
        x <span style="color: #66cc66;">=</span> <span style="color: black;">&#40;</span><span style="color: #ff7700;font-weight:bold;">yield</span><span style="color: black;">&#41;</span>
        ouput.<span style="color: black;">send</span><span style="color: black;">&#40;</span>x * x<span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #66cc66;">@</span>coroutine
<span style="color: #ff7700;font-weight:bold;">def</span> filtrer_les_paires<span style="color: black;">&#40;</span>ouput<span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">while</span> <span style="color: #008000;">True</span>:
        x <span style="color: #66cc66;">=</span> <span style="color: black;">&#40;</span><span style="color: #ff7700;font-weight:bold;">yield</span><span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">if</span> x % <span style="color: #ff4500;">2</span> <span style="color: #66cc66;">==</span> <span style="color: #ff4500;">0</span>:
            ouput.<span style="color: black;">send</span><span style="color: black;">&#40;</span>x<span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #66cc66;">@</span>coroutine
<span style="color: #ff7700;font-weight:bold;">def</span> strigifier<span style="color: black;">&#40;</span>ouput<span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">while</span> <span style="color: #008000;">True</span>:
        x <span style="color: #66cc66;">=</span> <span style="color: black;">&#40;</span><span style="color: #ff7700;font-weight:bold;">yield</span><span style="color: black;">&#41;</span>
        ouput.<span style="color: black;">send</span><span style="color: black;">&#40;</span><span style="color: #008000;">str</span><span style="color: black;">&#40;</span>x<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #66cc66;">@</span>coroutine
<span style="color: #ff7700;font-weight:bold;">def</span> afficher<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">while</span> <span style="color: #008000;">True</span>:
        x <span style="color: #66cc66;">=</span> <span style="color: black;">&#40;</span><span style="color: #ff7700;font-weight:bold;">yield</span><span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span>x<span style="color: black;">&#41;</span>
&nbsp;
nombres <span style="color: #66cc66;">=</span> <span style="color: #008000;">range</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">10</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># chaque coroutine est la sortie d'une autre</span>
afficheur <span style="color: #66cc66;">=</span> afficher<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
fete_du_string <span style="color: #66cc66;">=</span> strigifier<span style="color: black;">&#40;</span>afficheur<span style="color: black;">&#41;</span>
paires <span style="color: #66cc66;">=</span> filtrer_les_paires<span style="color: black;">&#40;</span>fete_du_string<span style="color: black;">&#41;</span>
carre <span style="color: #66cc66;">=</span> mettre_au_carre<span style="color: black;">&#40;</span>paires<span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># on envoit les données vers la première coroutine</span>
<span style="color: #808080; font-style: italic;"># et elle fait suivre aux autres</span>
<span style="color: #ff7700;font-weight:bold;">for</span> x <span style="color: #ff7700;font-weight:bold;">in</span> nombres:
    carre.<span style="color: black;">send</span><span style="color: black;">&#40;</span>x<span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #808080; font-style: italic;">## '0'</span>
<span style="color: #808080; font-style: italic;">## '4'</span>
<span style="color: #808080; font-style: italic;">## '16'</span>
<span style="color: #808080; font-style: italic;">## '36'</span>
<span style="color: #808080; font-style: italic;">## '64'</span></pre></td></tr></table></div>

<p>Vous allez me dire : &#8220;ça fait la même chose, et c&#8217;est plus compliqué, quel interêt ?&#8221;.</p>
<p>En fait, ça ne fait pas exactement la même chose.</p>
<p>Dans le cas des générateurs ordinaires, on déclenche le traitement par la fin. On fait une boucle qui demande quelle est la prochaine donnée, et si il y en a une, on l&#8217;affiche. C&#8217;est pratique si on sait qu&#8217;on a des données sous la main car on demande (<code>next()</code> est appelée par la boucle <code>for</code>) la donnée suivante à chaque fois : c&#8217;est du PULL.</p>
<p>Mais que se passe-t-il si on n&#8217;a pas encore les données ? Si on traite des données qui arrivent par évenement ?</p>
<p>Par exemple, si on écrit un serveur HTTP qui doit réagir aux requêtes ?</p>
<p>Dans ce cas, on ne peut envoyer (<code>send()</code>) la donnée suivante dans notre pipeline de générateurs uniquement quand elle arrive, et les coroutines font exactement cela : c&#8217;est du PUSH.</p>
<p>En résumé :</p>
<ul>
<li><code>yield</code> permet de faire des générateurs</li>
<li>On peut demander la prochaine valeur du générateur avec <code>next()</code>. Dans ce cas, le code s&#8217;exécute jusqu&#8217;au prochain <code>yield</code>.</li>
<li>On peut envoyer une valeur au générateur avec <code>send()</code>. Dans ce cas, on DOIT partir d&#8217;un <code>yield</code> existant duquel on récupère la valeur envoyée via une assignation. Donc il faut au moins un <code>next()</code> avant d&#8217;utiliser un <code>send()</code> et un signe égal sur le <code>yield</code>.</li>
<li><code>send()</code> va aussi aller au prochain <code>yield</code> et retourner sa valeur.</li>
<li>Une coroutine n&#8217;est qu&#8217;une formalisation de la manière d&#8217;éffectuer une tâche avec un init, une exécution et une finalisation optionelle en utilisant un générateur. C&#8217;est une solution générique à un problème courant, mais plus léger qu&#8217;une classe.</li>
<li>Généralement on décore les générateurs coroutines avec un décorateur <code>@coroutine</code> pour s&#8217;éviter d&#8217;appeler <code>next()</code> à la main et notifier l&#8217;usage qu&#8217;il est fait de ce générateur.</li>
<li>On peut chaîner des coroutines comme on chaîne des générateurs, mais au lieu de lire les données une à une (PULL), on les envoie une par une (PUSH). Cela est pratique quand on ne sait pas à l&#8217;avance quand une nouvelle donnée va arriver.</li>
</ul>
<p>Si vous êtes arrivé jusqu&#8217;ici, vous méritez un cookie.</p>
<p>Ca tombe bien, ce blog utilise des cookies, et la loi m&#8217;oblige à vous le notifier.</p>


feed_id: http://sametmax.com/?p=12867
title: Quand ne pas utiliser Python ?
uri: Quand-ne-pas-utiliser-Python-Recently-updated
url: http://sametmax.com/quand-ne-pas-utiliser-python/
content:
<p>J&#8217;ai lu récemment sur un forum la question &#8220;quand utiliser Python ?&#8221;. Mais la vérité c&#8217;est que Python est un langage globalement bon partout. En fait, <a href="http://sametmax.com/quest-ce-quon-peut-faire-avec-python/">on peut presque tout faire en Python</a> car c&#8217;est un langage <a href="http://sametmax.com/10-raisons-pour-lesquelles-je-suis-toujours-marie-a-python/">bourré de qualités</a> avec <a href="http://pyvideo.org/">une belle communauté</a> et <a href="http://sametmax.com/tres-grand-listing-des-libs-tierce-partie-les-plus-utiles-en-python/">des libs pour presque tout</a>.</p>
<p>Du coup, je pense qu&#8217;il est plus judicieux de se poser la question inverse : quand ne pas utiliser Python ?</p>
<p>Pour le moment, j&#8217;évite d&#8217;utiliser Python dans les cas suivants :</p>
<ul>
<li>L&#8217;équipe avec laquelle je travaille est bien meilleure dans un autre langage. Il faut profiter des compétences de chacun au maximum plutôt que privilégier une technologie, c&#8217;est plus productif.</li>
<li>Je reprends du code d&#8217;un projet solide, dans un autre langage. Inutile de réécrire quelque chose qui est propre et qui fonctionne.</li>
<li>Je travaille dans un environnement où d&#8217;autres technologies sont mieux intégrées. Par exemple, dans une entreprise avec une forte culture Java, faire les choses dans son coin ne va pas permettre un bon travail d&#8217;équipe. Travailler avec une boîte qui a des serveurs qu&#8217;ils ne peuvent pas changer et d&#8217;autres technos ? Inutile de forcer la main.</li>
<li>Des technologies plus productives existent pour ce domaine : c&#8217;est le cas de l&#8217;embarqué, ou des jeux vidéos. Ça ne veut pas dire qu&#8217;on ne peut pas en faire en Python. En fait, il y a un fort travail de la communauté pour améliorer cela en ce moment même. Mais difficile de combattre les outils en C/C++ dans ces domaines.</li>
<li>Je suis pressé, et la solution de facto n&#8217;est pas en Python. Par exemple, je veux faire du Web temps réel. Si j&#8217;ai le temps, je ferai du Python, car ce n&#8217;est pas grave si il me faut aiguiser moi-même quelques outils pour obtenir le résultat désiré. Si par contre j&#8217;ai 2 semaines devant moi, je prendrais NodeJS, malgré <a href="http://sametmax.com/un-gros-troll-de-plus-sur-javacscript/">mon dégoût pour le Javascript</a>, car je suis pragmatique. </li>
<li>J&#8217;ai <strong>mesuré</strong> mes besoins objectivement, et est évalué que Python ne serait pas assez performant malgré toute les mesures d&#8217;optimisation que je sais mettre en œuvre. Dans ce cas, on se tourne vers des solutions plus lourdes mais nativement plus rapides : C, GO, Erlang etc.</li>
<li>Je vise une plateforme en particulier (Windows, iOS&#8230;), je n&#8217;ai pas besoin de porter mon code, et je sais qu&#8217;utiliser les outils de la boîte qui fait l&#8217;OS me donnera de meilleurs résultats. Par exemple si je vise Android uniquement, utiliser leur SDK donnera une app plus fluide et une UI mieux intégrée.</li>
</ul>
<p>Dans tous les autres cas, Python est un choix excellent.</p>


feed_id: http://sametmax.com/?p=12883
title: Full disclosure 26 &#160; Recently updated !
uri: Full-disclosure-Recently-updated
url: http://sametmax.com/full-disclosure/
content:
<p>Depuis quelques jours je suis en discussion avec Tobias de Tavendo. Comme vous avez pu le remarquer avec mes précédents articles sur <a href="http://sametmax.com/crossbar-le-futur-des-applications-web-python/">WAMP</a> et <a href="http://sametmax.com/le-potentiel-de-wamp-autobahn-et-crossbar-io/">Crossbar</a> :</p>
<ul>
<li>Ils sont bons techniquement, et nuls pour expliquer ce qu&#8217;ils ont techniqué.</li>
<li>Cette techno est une techno de rêve pour moi. J&#8217;y crois à mort.</li>
<li>Je suis le seul à avoir pondu des explications décentes sur WAMP et Crossbar. Et ça n&#8217;a pas suffit à faire battre un cil.</li>
</ul>
<p>Bref, ils ont embauché des mecs de haute voltige pour la technique (du genre un contributeur PyPy). Et ils m&#8217;ont contacté pour me demander si je n&#8217;étais pas chaud pour faire de l&#8217;évangélisme, rémunéré, autour de WAMP, Autobahn et Crossbar.</p>
<p>L&#8217;idée : écrire des tutos, des articles, améliorer la doc, répondre sur le chan IRC, etc.</p>
<p>J&#8217;adore le concept, vu que j&#8217;aime leur projet et que je le faisais gratos avant, surtout qu&#8217;ils sont pas trop contraignants sur le temps que je vais passer dessus.</p>
<p>Donc voilà le deal : quand je vais pondre des tutos et des articles sur WAMP et Co, je vais d&#8217;abord les faire en français ici. Comme ça j&#8217;aurai les retours des lecteurs du blog qui pourront, comme d&#8217;habitude, me faire part de leurs douces remarques sur à quel point on ne pige rien.</p>
<p>Une fois la prose aiguisée, je traduis et je publie chez Tavendo.</p>
<p>Je disclose donc ici que vous verrez peut-être des prochaines rédactions qui seront attachées à une activité pro. Pas impartial donc. Mais bon, depuis quand je suis impartial ? Javascript c&#8217;est de la merde, et je préfère les rousses.</p>
<p>Par saucisse d&#8217;honnêteté, je signalerai chaque choucroute concernée avec un lien vers ce post.</p>
<p>Enfin, le contrat est pas signé encore, mais vu que je vais commencer à taffer dessus aujourd&#8217;hui, je pense à une première publication demain sous la forme d&#8217;un slide show expliquant avec de jolies diapos ce que sont WAMP, Autobahn et Crossbar. À quoi ça sert et ce qu&#8217;on peut faire avec.</p>


feed_id: http://sametmax.com/?p=12902
title: Travailler à deux sur iPython à distance 11
uri: Travailler-à-deux-sur-iPython-à-distance
url: http://sametmax.com/travailler-a-deux-sur-ipython-a-distance/
content:
<p>Bon, j&#8217;ai pas fini mon slideshow sur WAMP, donc je vais faire un article sur ça.</p>
<p><a href="http://sametmax.com/profiter-du-notebook-de-ipython/">iPython notebook</a>, c&#8217;est pratique, mais une seule personne peut coder à la fois. Si quelqu&#8217;un veut voir les changements, il faut recharger avec F5. A l&#8217;heure des Google Doc temps réel, c&#8217;est con. Surtout que c&#8217;est du ZMQ derrière.</p>
<p>Du coup je me suis lancé dans une expérimentation avec <a href="https://togetherjs.com/docs/">TogetherJS</a>, la lib de Momo pour le travail collaboratif.</p>
<p>Pour lancer le truc, il suffit d&#8217;aller dans son dossier de profile iPython et éditer le fichier Javascript vierge fait pour étendre l&#8217;outil. Par exemple, sous Ubuntu, mon profile par défaut est dans <code>~/ipython/profile_default</code> et le fichier à éditer est <code>./profile_default/static/custom/custom.js</code>.</p>
<p>Dedans on met :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;">TogetherJSConfig_autoStart <span style="color: #66cc66;">=</span> true<span style="color: #66cc66;">;</span>
TogetherJSConfig_cloneClicks <span style="color: #66cc66;">=</span> false<span style="color: #66cc66;">;</span>
TogetherJSConfig_dontShowClicks <span style="color: #66cc66;">=</span> true<span style="color: #66cc66;">;</span>
$.<span style="color: black;">getScript</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'https://togetherjs.com/togetherjs-min.js'</span><span style="color: black;">&#41;</span><span style="color: #66cc66;">;</span></pre></td></tr></table></div>

<p>Et on est bon. Il faut ouvrir deux browsers différents pour bien tester le truc, par exemple un chrominou et un firefoune. Moi j&#8217;ai ouvert deux FF parce que j&#8217;ai pleins de profiles dessus.</p>
<p>La frappe est bien synchro, mais malheureusement pas l&#8217;affichage du résultat. Y a donc bien un truc intéressant à creuser, mais pour le moment, c&#8217;est pas utilisable.</p>
<p>Ensuite, il y a des services Web. <a href="https://cloud.sagemath.com/">SageMathCloud</a> annonce faire cela, mais impossible de s&#8217;inscrire, le formulaire ne marche pas. <ahref="https://www.codebox.io">Codebox</ahref=> propose un env complet de dev en ligne, mais l&#8217;inscription est temporairement suspendue. <a href="http://codebunk.com">Codebunk</a> marche pas mal, est plutôt bien foutu et clair, mais Python 2.7 uniquement, et aucun moyen d&#8217;installer une lib, donc adieu scipy ou matplotlib.</p>
<p>Celui qui s&#8217;en rapproche le plus est <a href="https://www.pythonanywhere.com">Pythonanywhere</a> : des consoles synchronisées pour toutes les versions de Python, beaucoup de libs préinstallées (dont scipy et matplotlib), un vrai système de fichier sur lequel travailler, du pip a dispo. Et en prime un éditeur de texte pour des fichiers complets, mais qui lui, n&#8217;est pas collaboratif. Damn it. Et impossible d&#8217;afficher en ligne une image pondue via matplotlib. En plus, on a pas le concept des cellules d&#8217;iPython, qui est super pratique.</p>
<p>Bref, il manque vraiment un outil pour faire ce genre de choses.</p>


feed_id: http://sametmax.com/?p=12923
title: Petit à petit, on reconstruit 24
uri: Petit-à-petit-on-reconstruit-Recently-updated
url: http://sametmax.com/petit-a-petit-on-reconstruit/
content:
<p>Certains l&#8217;auront noté, les tampons sont de retour.</p>
<p>J&#8217;ai aussi, à la demande d&#8217;un lecteur, ajouté un plugin pour permettre aux commentaires d&#8217;être écrits en markdown (avec les extensions de github).</p>
<p>Pour obtenir la parité avec le précédent blog, il nous faudra donc restaurer encore quelques easter eggs et améliorer les images sur la page d&#8217;accueil, mais c&#8217;est presque fini. Comme quoi, une migration, c&#8217;est long. Et chiant. Et ingrat.</p>


feed_id: http://sametmax.com/?p=12939
title: Mieux que Python virtualenvwrapper : pew 8 &#160; Recently updated !
uri: Mieux-que-Python-virtualenvwrapper-pew-Recently-updated
url: http://sametmax.com/mieux-que-python-virtualenvwrapper-pew/
content:
<p>Vous avez compris que Python sans <a href="http://sametmax.com/les-environnement-virtuels-python-virtualenv-et-virtualenvwrapper/">virtualenv</a> c&#8217;est comme la mer sans les vagues, c&#8217;est comme les vagues sans l&#8217;écume, c&#8217;est comme l&#8217;écume sans le sel, c&#8217;est comme le sel sans le poivre&#8230;</p>
<p>Mais c&#8217;est aussi appétissant que les méduses échouées.</p>
<p>Donc pour se faciliter la vie, vous utilisez virtualenvwrapper.</p>
<p>Et bien il y a plus meilleur : <a href="https://github.com/berdario/pew#usage">pew</a>.</p>
<p>Non content d&#8217;avoir un nom cool et court, c&#8217;est un progrès non négligeable dans l&#8217;ergonomie de notre vie de dresseur de reptiles.</p>
<p>D&#8217;abord : <code><a href="http://sametmax.com/votre-python-aime-les-pip/">pip</a> install pew</code>.</p>
<p>Ensuite, tableau d&#8217;équivalence avec virtualenvwrapper :</p>
<table class="tableizer-table">
<tbody>
<tr class="tableizer-firstrow">
<th></th>
<th>virtualenvwrapper</th>
<th>pew</th>
</tr>
<tr>
<td>Lister les env existant</td>
<td>workon</td>
<td>pew ls</td>
</tr>
<tr>
<td>Créer un env</td>
<td>mkvirtualenv name</td>
<td>pew new name</td>
</tr>
<tr>
<td>Supprimer un env</td>
<td>rmvirtualenv name</td>
<td>pew rm name</td>
</tr>
<tr>
<td>Activer un env</td>
<td>workon name</td>
<td>pew workon name</td>
</tr>
<tr>
<td>Aller dans le dossier site-packages</td>
<td>cdsitepackages</td>
<td>cd $(pew sitepackages_dir)</td>
</tr>
<tr>
<td>Valeur par défaut pour $WORKON_HOME (dossier qui contient tous les envs)</td>
<td>~/.virtualenvs</td>
<td>~/local/share/virtualenvs</td>
</tr>
</tbody>
</table>
<p>Vous noterez que les commandes de pew sont plus faciles à retenir, plus cohérentes, et toutes des sous-commandes histoire d&#8217;éviter de pourrir son espace de nom.</p>
<p>Autres avantages : pew n&#8217;a pas besoin qu&#8217;on ajoute un fichier à votre <code>.bashrc</code> pour marcher. Car pew ne source pas un env dans votre shell courant, il ouvre un nouveau shell. Pour sortir de l&#8217;env, c&#8217;est donc un simple <kbd>Ctrl</kbd> + <kbd>D</kbd>.</p>
<p>Seulement ça ne s&#8217;arrête pas là. Pew possède quelques commandes bonus qui changent bien la vie :</p>
<table class="tableizer-table">
<tbody>
<tr class="tableizer-firstrow">
<th></th>
<th>virtualenvwrapper</th>
<th>pew</th>
</tr>
<tr>
<td>Éxecuter la commande dans un env sans l&#8217;activer</td>
<td>Nope</td>
<td>pew in name commande</td>
</tr>
<tr>
<td>Éxecuter la commande dans tous les env</td>
<td>Non</td>
<td>pew inall commande</td>
</tr>
<tr>
<td>Dupliquer un virtualenv ailleurs</td>
<td>Nada</td>
<td>pew cp name destination</td>
</tr>
<tr>
<td>Ajouter un chemin au PYTHONPATH de l&#8217;env</td>
<td>Fuck it</td>
<td>pew add path</td>
</tr>
<tr>
<td>Changer la prise en compte des libs du site-packages du système quand on veut</td>
<td>I&#8217;m out</td>
<td>pew toggleglobalsitepackages</td>
</tr>
<tr>
<td>Créer un env temporaire supprimé dès qu&#8217;on en sort</td>
<td>Now you are just pushing it</td>
<td>pew mktmpenv</td>
</tr>
<tr>
<td>Choisir un dossier vers lequel aller à l&#8217;activation de l&#8217;env</td>
<td>BANG !</td>
<td>pew setproject path</td>
</tr>
</tbody>
</table>
<p>Bon, le seul truc qui manque pour le moment, ce sont les hooks.</p>


feed_id: http://sametmax.com/?p=12948
title: Message de service aux débutants en Python 24
uri: Message-de-service-aux-débutants-en-Python-Recently-updated
url: http://sametmax.com/message-de-service-aux-debutants-en-python/
content:
<p>Ces informations sont éparpillées sur le net, et même sur le blog. Mais c&#8217;est un peu le package que tout dev Python qui se lance doit apprendre petit à petit. Alors je vais vous épargner les recherches.</p>
<p>Ne prenez pas ça comme une checklist qu&#8217;il faut impérativement faire avant de programmer. Coder est le plus important pour apprendre. Tout le reste est facultatif. Mais cet article liste des raccourcis qui vous seront utiles au fur et à mesure de votre progression.</p>
<h2>Réponse aux grandes questions de la vie</h2>
<h3>J&#8217;installe Python avec quoi ?</h3>
<p>Sous Linux, avec votre gestionnaire de paquet. Mais souvenez-vous que la 2.7 est installée par défaut.</p>
<p>Sous Mac, avec <a href="http://brew.sh/">homebrew</a>. Mais souvenez-vous que la 2.7 est installée par défaut. Vous aurez besoin de GCC. Mais pas besoin de télécharger xcode pour ça, il y a des <a href="https://github.com/kennethreitz/osx-gcc-installer">solutions légères</a>.</p>
<p>Sous Windows, utilisez <a href="http://conda.pydata.org/miniconda.html">miniconda</a>. L&#8217;installeur officiel est pas mal, mais miniconda vous aidera beaucoup pour plein de choses, comme installer facilement les extensions compilées type scipy ou QT. Et cochez toujours l&#8217;option pour ajouter Python au SYSTEM PATH, sinon il faudra <a href="http://sametmax.com/ajouter-un-chemin-a-la-variable-denvironnement-path-sous-windows/">le faire à la main</a> et c&#8217;est relou.</p>
<h3>Python 2 or Python 3 ?</h3>
<p>Python 3 sauf si :</p>
<ul>
<li>Vous êtes certain de devoir utiliser une lib en rouge dans <a href="https://python3wos.appspot.com/">cette liste</a>.</li>
<li>Vous êtes sur Mac ou Linux, et vous avez pas envie de vous faire chier à installer Python 3 alors que Python 2.7 est déjà là par défaut.</li>
<li>Vous n&#8217;avez pas accès à Python 3.3 ou 3.4. Les premières versions de Python 3 sont horribles.</li>
</ul>
<p>Dans tous les cas, souvenez-vous :</p>
<ul>
<li>Qu&#8217;on peut installer plusieurs versions en même temps.</li>
<li>Que passer de l&#8217;un à l&#8217;autre n&#8217;est pas difficile. On peut même écrire du code compatible avec les deux si besoin même si c&#8217;est un peu chiant.</li>
<li>La commande <code>py</code> permet de choisir quel Python lancer sous Windows (<code>py -2 </code>ou <code>py -3</code>). Sous linux, on peut carrément faire <code>python2</code> ou <code>python3</code>, ou <code>python3.4</code>.</li>
<li>Les environnement virtuels peuvent utiliser une version de Python en particulier avec <code>-p.</code></li>
</ul>
<h3>Mais c&#8217;est quoi cette histoire de CPython, Pypy, IronPython, Jython, Julia, Cython, Nuitka, Hope&#8230;</h3>
<p>Y a combien de Python bordel ?</p>
<p>Pour vous, un seul : CPython. C&#8217;est-à-dire ce que les gens appellent &#8220;Python&#8221;.</p>
<p>Vous pouvez ignorer le reste. Vous n&#8217;avez pas à vous inquiéter de devoir utiliser un autre un jour, devoir passer à un autre, etc. Ce sont juste des bonus qui peuvent aider des gens dans des cas particuliers, rien d&#8217;indispensable.</p>
<h3>Pip ou easy_install</h3>
<p>pip. <a href="http://sametmax.com/votre-python-aime-les-pip/">Installez toujours pip</a>. Utilisez toujours pip. Apprenez à bien utiliser pip avec toutes ses options.</p>
<p>Et souvenez-vous qu&#8217;on peut installer un module pour une version de python en particulier en faisant <code>pythonX -m pip</code> ou sous windows, <code>py -x -m pip</code>.</p>
<p>Une exception pour les extensions :</p>
<p>Si vous êtes sous Windows, installer <strong>en plus</strong> miniconda va vous simplifier énormément la vie pour installer les extensions compilées comme scipy.</p>
<p>Et si vous êtes sous Linux utilisez votre gestionnaire de paquet sans quoi vous allez devoir installer gcc et les headers de Python (package python-dev sous Ubuntu par exemple).</p>
<h3>distutils, setuptools ou distribute ?</h3>
<p>Setuptools. Le reste a été fusionné ou déprécié.</p>
<h3>Python 32 bits ou python 64 bits ?</h3>
<p>64 bits. Si vous avez un jour une erreur indébuggable sous windows, testez avec une version 32 bits au cas où. Mais 64 bits reste le choix par défaut.</p>
<h3>Quel IDE ?</h3>
<p>Aucun IDE n&#8217;est nécessaire en Python. On peut coder avec un simple éditeur de texte et la console. Je fais toutes mes formations avec Notepad++ sous Windows, ou Gedit sous Ubuntu.</p>
<p>Vous pouvez donc juste utiliser ce que vous aimez le plus.</p>
<h3>Pour UI, PyQt, PySide, wxPython, Kivy, PyGTK, Tkinter ?</h3>
<p><a href="https://docs.python.org/2/library/tkinter.html">Tkinter</a> si c&#8217;est une UI simple (quelques fenêtres, quelques formulaires). <a href="http://wxpython.org/">WxPython</a> si c&#8217;est un programme complexe en Python 2.7. C&#8217;est le meilleur équilibre poids/puissance. <a href="http://kivy.org/">Kivy</a> si ça doit tourner sur mobile.</p>
<p><a href="http://www.riverbankcomputing.co.uk/software/pyqt/intro">PyQt</a>/<a href="http://qt-project.org/wiki/PySide">PySide</a> sont les plus puissants, mais beaucoup plus dur à utiliser. Ca vaut rarement le coup, sauf que pour le moment, c&#8217;est la seule solution solide en Python 3.</p>
<h2>Les outils qui changent la vie</h2>
<p>On peut coder avec Python sans tout ça, mais la vie est plus belle avec.</p>
<ul>
<li>pip permet d&#8217;installer facilement plein de libs.</li>
<li><a href="http://ipython.org/">ipython</a>, un shell Python qui facilite l&#8217;expérimentation de code.</li>
<li><a href="http://sametmax.com/debugger-en-python-les-bases-de-pdb/">pdb</a> permet de débugger votre programme. <a href="https://pypi.python.org/pypi/pdbpp/">pdb++</a> en bonus.</li>
<li><a href="http://sametmax.com/les-environnement-virtuels-python-virtualenv-et-virtualenvwrapper/">virtualenv</a> vous permet d&#8217;avoir des installations de Python différentes pour chaque projet avec des libs isolées. Avec <a href="http://sametmax.com/mieux-que-python-virtualenvwrapper-pew/">pew</a> en bonus.</li>
<li><a href="http://sametmax.com/grin-le-grep-python-sous-steroid/">grin</a>, pour rechercher un mot dans votre code. Mieux que grep et marche sous Windows.</li>
<li><a href="http://sametmax.com/remplacer-sed-awk-cut-et-perl-par-python-orgasme-pour-sysadmin/">pyped</a>, pour remplacer sed, cut, awk et bien plus par du python simple, y compris sous Windows</li>
</ul>
<p>Si vous êtes sous windows, souvenez-vous que <kbd>Shift</kbd> avant un clic droit ajoute des options supplémentaires au menu contextuel de votre explorateur de fichiers. Avec notamment &#8220;Ouvrir une invite de commande dans ce dossier&#8221;. Sous Mac il y a un <a href="http://hdrapin.com/2013/02/17/mac-comment-ouvrir-le-dossier-selectionne-dans-le-terminal/">réglage</a> pour ça. <a href="http://www.distrogeeks.com/open-terminal-here-ubuntu/">Sous Ubuntu il y a un plugin</a>.</p>
<p>Ah oui, et sous windows, utilisez <a href="https://github.com/cbucher/console/wiki/Downloads">une console décente</a>.</p>
<h2>Bonnes habitudes</h2>
<p>Réglez votre éditeur de texte pour utiliser 4 espaces pour indenter. Si vous préférez les tabs, réglez aussi votre éditeur de texte pour utiliser 4 espaces pour indenter.</p>
<p>Tant qu&#8217;on y est, <a href="http://sametmax.com/lencoding-en-python-une-bonne-fois-pour-toute/">apprenez à gérer votre encoding</a>. Particulièrement, assurez-vous de savoir où changer l&#8217;encoding des caractères de vos fichiers dans les options de votre éditeur de texte. Et mettez le par défaut sur UTF8. Utilisez toujours des chaînes de caractères unicode et le header <code># -*- coding: utf-8 -*-</code>.</p>
<p>Utilisez <code>print</code> avec la syntaxe sous forme de fonction. Et faites des imports absolus, jamais relatifs.</p>
<p>En fait, si vous êtes en Python 2.7, activez le plus de comportement de Python 3 possible en faisant les imports de <code>__future__</code>.</p>
<p>Pour un débutant, voici donc un bon template de fichier Python 2.7 par défaut :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #808080; font-style: italic;"># -*- coding: utf-8 -*-</span>
&nbsp;
<span style="color: #483d8b;">&quot;&quot;&quot;
    Documenter le module ici.
&quot;&quot;&quot;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">from</span> <span style="color: #dc143c;">__future__</span> <span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: black;">&#40;</span>unicode_literals<span style="color: #66cc66;">,</span> absolute_import<span style="color: #66cc66;">,</span>
                        print_function<span style="color: #66cc66;">,</span> division<span style="color: black;">&#41;</span>
&nbsp;
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> main<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    <span style="color: #483d8b;">&quot;&quot;&quot; Run the whole program &quot;&quot;&quot;</span>
    <span style="color: #808080; font-style: italic;"># votre code ici</span>
    <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'Hello !'</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">if</span> __name__ <span style="color: #66cc66;">==</span> <span style="color: #483d8b;">'__main__'</span>:
    main<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span></pre></td></tr></table></div>

<ul>
<li><strong>unicode_literals</strong> : active les chaînes unicode par défaut.</li>
<li><strong>absolute_import</strong> : active les imports absolus par défaut.</li>
<li><strong>print_function</strong> : remplace le mot clé <strong>print</strong> par la fonction <strong>print()</strong>.</li>
<li><strong>division</strong> : <code>/</code> devient la division classique, <code>//</code> la division entière.</li>
</ul>
<p>Pour Python 3, c&#8217;est plus simple :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #483d8b;">&quot;&quot;&quot;
    Documenter le module ici.
&quot;&quot;&quot;</span>
&nbsp;
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> main<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    <span style="color: #483d8b;">&quot;&quot;&quot; Run the whole program &quot;&quot;&quot;</span>
    <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'Hello !'</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">if</span> __name__ <span style="color: #66cc66;">==</span> <span style="color: #483d8b;">'__main__'</span>:
    main<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>Utilisez toujours des dates en UTC. Ne convertissez qu&#8217;à l&#8217;affichage. Donc ça veut dire utiliser <code>datetime.utcnow()</code> et non <code>datetime.now()</code></p>
<h2>Des libs qu&#8217;on les aime</h2>
<p>Les modules disponibles avec Python sont ce qu&#8217;on appelle la bibliothèque standard, ou stdlib. Il y a beaucoup de modules <a href="http://sametmax.com/tres-grand-listing-des-libs-standard-partie-les-plus-utiles-en-python/">très utiles</a>.</p>
<p>Néanmoins certains doivent avoir la priorité dans votre apprentissage. Les plus importants sont :</p>
<ul>
<li><a href="https://docs.python.org/2/library/os.html?highlight=os#module-os">os</a>, <a href="https://docs.python.org/2/library/shutil.html?highlight=shutils">shutil</a>, <a href="https://docs.python.org/2/library/subprocess.html?highlight=subprocess">subprocess</a> et <a href="https://docs.python.org/2/library/sys.html?highlight=sys#module-sys">sys</a> : manipuler votre OS, des fichiers aux processus.</li>
<li><a href="https://docs.python.org/2/library/datetime.html?highlight=datetime#module-datetime">datetime</a> : manipuler les dates.</li>
<li><a href="https://docs.python.org/2/library/math.html?highlight=math#module-math">math</a> et <a href="https://docs.python.org/2/library/decimal.html?highlight=decimal#module-decimal">decimal</a> : ben, les maths.</li>
<li><a href="https://docs.python.org/2/library/collections.html?highlight=collection#module-collections">collections</a> : des structures de données avancées.</li>
<li><a href="https://docs.python.org/2/library/decimal.html?highlight=decimal#module-decimal">argparse</a> : faire un script avec des paramètres.</li>
<li><a href="https://docs.python.org/2/library/urllib2.html?highlight=urllib#module-urllib2">urllib2</a> : faire des requêtes HTTP.</li>
<li><a href="https://docs.python.org/2/library/itertools.html?highlight=itertools#module-itertools">itertools</a> : l&#8217;itération est tout en Python.</li>
</ul>
<p>Quelques modules sont vieux, et ça se sent dans leur facilité d&#8217;usage. Pour cette raison, si vous utilisez beaucoup certains d&#8217;entre eux, des alternatives installables avec pip peuvent vous simplifier <strong>énormément</strong> la vie :</p>
<table class="tableizer-table">
<tbody>
<tr>
<td>Stdlib</td>
<td>Lib tierce partie plus pratique&gt;</td>
</tr>
<tr class="tableizer-firstrow">
<td>datetime</td>
<td><a href="http://sametmax.com/les-time-zones-en-python/">arrow</a></td>
</tr>
<tr>
<td>os, sys, shutil</td>
<td><a href="http://sametmax.com/path-py-plus-en-detail/">path.py</a></td>
</tr>
<tr>
<td>argparse</td>
<td><a href="http://sametmax.com/la-plus-belle-maniere-de-parser-les-arguments-de-script-en-python/">docopt</a></td>
</tr>
<tr>
<td>unittest</td>
<td><a href="http://sametmax.com/se-simplifier-les-tests-python-avec-pytest/">pytest</a>. En fait ne faites jamais de <a href="http://sametmax.com/un-gros-guide-bien-gras-sur-les-tests-unitaires-en-python-partie-1/">tests unitaires</a> sans pytest. La vie est trop courte.</td>
</tr>
<tr>
<td>urllib2</td>
<td><a href="http://docs.python-requests.org/en/latest/">requests</a></td>
</tr>
</tbody>
</table>
<h2>Y a des priorités dans la vie</h2>
<p>Les trucs importants à apprendre en Python (qui sont typiques de ce langage, j&#8217;entends) avant de se lancer dans la sophistication :</p>
<ul>
<li>Toutes les choses ont une valeur booléenne. Savoir en tirer parti.</li>
<li>Connaitre toutes les méthodes des strings.</li>
<li>Les exceptions : try, except, else, finally, raise.</li>
<li>Maitriser le slicing et l&#8217;unpacking.</li>
<li><a href="http://sametmax.com/operateur-splat-ou-etoile-en-python/">L&#8217;opérateur splat</a>.</li>
<li>Manipuler des fichiers.</li>
<li>Les dictionnaires et les sets. Vous les sous-utilisez. Étudiez-les.</li>
<li>Bien maitriser l&#8217;itération : for, else, continue, break.</li>
<li>Bien maitriser l&#8217;itération (bis) : zip, enumerate, sorted, reversed, any, all&#8230;</li>
<li>Bien maitriser l&#8217;itération (ter) : <a href="http://sametmax.com/python-love-les-listes-en-intention-partie/">les listes en intension</a>.</li>
<li>Bien maitriser l&#8217;itération (vous-ai je dit que c&#8217;était tout en Python ?) : <a href="http://sametmax.com/comment-utiliser-yield-et-les-generateurs-en-python/">les générateurs</a>.</li>
<li>Les regex. C&#8217;est chiant. Je sais. Mais c&#8217;est trop puissant pour être ignoré.</li>
</ul>
<p>Avec ça vous pouvez aborder sereinement tout problème. Le reste, c&#8217;est du bonus.</p>
<p>Typiquement, on peut repousser à bien plus tard l&#8217;apprentissage de :</p>
<ul>
<li><a href="http://sametmax.com/fonctions-anonymes-en-python-ou-lambda/">Les lambdas</a>.</li>
<li><a href="http://sametmax.com/comprendre-les-decorateurs-python-pas-a-pas-partie-1/">Decorateurs</a>.</li>
<li>Les <a href="http://sametmax.com/les-context-managers-et-le-mot-cle-with-en-python/">context managers</a>.</li>
<li>L&#8217;introspection.</li>
<li><a href="http://sametmax.com/le-guide-ultime-et-definitif-sur-la-programmation-orientee-objet-en-python-a-lusage-des-debutants-qui-sont-rassures-par-les-textes-detailles-qui-prennent-le-temps-de-tout-expliquer-partie-1/">La programmation orientée objet</a>.</li>
<li>Metaclasses.</li>
</ul>


