# articles

feed_id: http://sametmax.com/?p=7096
title: Le colonel moutarde dans la cuisine avec le chandelier
uri: Le-colonel-moutarde-dans-la-cuisine-avec-le-chandelier
url: http://sametmax.com/le-colonel-moutarde-dans-la-cuisine-avec-le-chandelier/
content:
<p style="text-align: center;"><em><small>Ceci est un post invité de <a href="http://sametmax.com/author/golgotha/">Golgotha</a> posté sous licence <a href="http://creativecommons.org/licenses/by/3.0/">creative common 3.0 unported</a>.</small></em></p>
<p>On a parfois du mal à localiser l&#8217;origine d&#8217;un bug dans une longue requête sql ou un code spaghetti de 5000 lignes écris en 1999 par un biologiste recruté dans une SSII. Bien sur vous pouvez tenter la méthode traditionnelle, essayer de comprendre d&#8217;où viens le bug, de façon logique&#8230; ou bien gagner du temps et appliquer la méthode que je préfère dans ce genre de situation : la dichotomie.</p>
<p>Le principe est simple, couper en deux le code défectueux (commenter la moitié), re-faire un test, si le code marche, l&#8217;erreur viens de la partie commentée ou inversement, ensuite prenez la partie défectueuse et recommencez. Vous tomberez assez rapidement sur le bug, généralement en quelques minutes grand max, sans avoir réfléchi, c&#8217;est pratique quand vous devez trouver un bug rapidement en prod dans la panique générale.</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=7096&amp;md5=0e9a509ae2e1be5abdd1c563833415fa" title="Flattr" target="_blank"><img src="media/fc229d00.flattr-badge-large.png" data-original-source="http://sametmax.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>


feed_id: http://sametmax.com/?p=7112
title: Objets proxy et pattern adapter en Python
uri: Objets-proxy-et-pattern-adapter-en-Python
url: http://sametmax.com/objets-proxy-et-pattern-adapter-en-python/
content:
<p>En informatique, le vocabulaire c&#8217;est une bonne partie du travail. On a des tas de termes comme polymorphisme, récursivité, idempotent ou closure. Certains sont des termes mathématiques, d&#8217;autres sont des anglicismes, mais la majorité sont juste des mots compliqués pour décrire des choses simples.</p>
<p>Vous connaissez mon manque d&#8217;attrait pour ça, on va donc clarifier.</p>
<p>Pour comprendre cet article, il vous faut les pré-requis suivants :</p>
<ul>
<li>Être à l&#8217;aise avec avec la programmation orientée objet : héritage, property&#8230;</li>
<li>Bien comprendre la notion de référence.</li>
<li>Avoir un peu de temps devant soi.</li>
</ul>
<p>Et pour une fois, on va mettre un morceau qui colle bien au blog :</p>

<!-- iframe plugin v:2.3 - wordpress.org/extend/plugins/iframe/ -->
<iframe width="420" height="315" src="//www.youtube.com/embed/lqXRk-cmXwM" frameborder="0" scrolling="no" class="iframe-class"></iframe>
<h2>S&#8217;il vous plait, dessine moi un objet proxy</h2>
<p>Un proxy, en anglais, c&#8217;est un mandataire, c&#8217;est à dire grosso merdo un intermédiaire. Un objet proxy est donc tout simplement un objet qui fait l&#8217;intermédiaire, généralement entre un objet et un autre.</p>
<p>Exemple, on a des enseignants qui vont avoir besoin d&#8217;une autorisation de sortie pour des enfants dans leur classe. Un enfant ne peut pas décider de cela, ses parents décident de ce genre de chose :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">class</span> Enseignant<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;"># la demande d'autorisation attend un objet enfant en paramètre</span>
    <span style="color: #ff7700;font-weight:bold;">def</span> demande_autorisation_de_sortie<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, enfant<span style="color: black;">&#41;</span>:
        <span style="color: #ff7700;font-weight:bold;">return</span> enfant.<span style="color: black;">peut_sortir</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
&nbsp;
<span style="color: #ff7700;font-weight:bold;">class</span> Enfant<span style="color: black;">&#40;</span><span style="color: #008000;">object</span><span style="color: black;">&#41;</span>:
&nbsp;
    <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>, age<span style="color: black;">&#41;</span>:
        <span style="color: #008000;">self</span>.<span style="color: black;">age</span> = age
&nbsp;
    <span style="color: #808080; font-style: italic;"># mais un enfant ne peut pas donner cette information</span>
    <span style="color: #ff7700;font-weight:bold;">def</span> peut_sortir<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
        <span style="color: #ff7700;font-weight:bold;">raise</span> <span style="color: #008000;">NotImplementedError</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'Un enfant ne peut decider de cela'</span><span style="color: black;">&#41;</span>
&nbsp;
&nbsp;
<span style="color: #ff7700;font-weight:bold;">class</span> Parent<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;"># le parent va faire proxy sur l'objet enfant</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>, enfant<span style="color: black;">&#41;</span>:
        <span style="color: #008000;">self</span>.<span style="color: black;">enfant</span> = enfant
&nbsp;
    <span style="color: #808080; font-style: italic;"># et propose la même méthode que l'objet enfant afin de pouvoir</span>
    <span style="color: #808080; font-style: italic;"># être passé en paramètre à sa place à la méthode</span>
    <span style="color: #808080; font-style: italic;"># demande_autorisation_de_sortie()</span>
    <span style="color: #ff7700;font-weight:bold;">def</span> peut_sortir<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
        <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">self</span>.<span style="color: black;">enfant</span>.<span style="color: black;">age</span> <span style="color: #66cc66;">&gt;</span> <span style="color: #ff4500;">10</span></pre></div></div>

<p>Ici, si la classe <code>Enseignant</code> appelle directement la méthode <code>peut_sortir()</code> de la classe <code>Enfant</code>, on obtient une erreur. :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">&gt;&gt;&gt;</span> prof = Enseignant<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> enfant = Enfant<span style="color: black;">&#40;</span><span style="color: #ff4500;">11</span><span style="color: black;">&#41;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> prof.<span style="color: black;">demande_autorisation_de_sortie</span><span style="color: black;">&#40;</span>enfant<span style="color: black;">&#41;</span>
Traceback <span style="color: black;">&#40;</span>most recent call last<span style="color: black;">&#41;</span>:
  File <span style="color: #483d8b;">&quot;&lt;ipython-input-23-6d509f016e40&gt;&quot;</span>, line <span style="color: #ff4500;">1</span>, <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #66cc66;">&lt;</span>module<span style="color: #66cc66;">&gt;</span>
    prof.<span style="color: black;">demande_autorisation_de_sortie</span><span style="color: black;">&#40;</span>enfant<span style="color: black;">&#41;</span>
  File <span style="color: #483d8b;">&quot;&lt;ipython-input-18-e8d34178df4c&gt;&quot;</span>, line <span style="color: #ff4500;">4</span>, <span style="color: #ff7700;font-weight:bold;">in</span> demande_autorisation_de_sortie
    <span style="color: #ff7700;font-weight:bold;">return</span> enfant.<span style="color: black;">peut_sortir</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
  File <span style="color: #483d8b;">&quot;&lt;ipython-input-18-e8d34178df4c&gt;&quot;</span>, line <span style="color: #ff4500;">13</span>, <span style="color: #ff7700;font-weight:bold;">in</span> peut_sortir
    <span style="color: #ff7700;font-weight:bold;">raise</span> <span style="color: #008000;">NotImplementedError</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'Un enfant ne peut decider de cela'</span><span style="color: black;">&#41;</span>
<span style="color: #008000;">NotImplementedError</span>: Un enfant ne peut decider de cela</pre></div></div>

<p>Nous avons créé un système où on est obligé de créer une instance de <code>Parent</code>, qui va se placer entre la classe <code>Enseignant</code> et la classe <code>Enfant</code>, et qui va retourner la valeur pour cette méthode :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">&gt;&gt;&gt;</span> parent = Parent<span style="color: black;">&#40;</span>enfant<span style="color: black;">&#41;</span> <span style="color: #808080; font-style: italic;"># on passe l'enfant en paramètre au parent</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> prof.<span style="color: black;">demande_autorisation_de_sortie</span><span style="color: black;">&#40;</span>parent<span style="color: black;">&#41;</span> <span style="color: #808080; font-style: italic;"># et le parent remplace l'enfant</span>
<span style="color: #008000;">True</span></pre></div></div>

<p>Ceci est un objet proxy, c&#8217;est à dire un objet qui se place entre deux objets, et fait l&#8217;intermédiaire. <strong>Pour que cela marche, il faut que l&#8217;objet proxy, ici l&#8217;instance de <code>Parent</code>, ait la même interface (les mêmes méthodes, avec les mêmes paramètres et noms) que l&#8217;objet derrière le proxy, ici l&#8217;instance de <code>Enfant</code>.</strong></p>
<p>Dans notre cas, c&#8217;est académique, ça ne sert pas à grand chose. Mais il y a des tas de cas utiles pour les objets proxy.</p>
<p>Ainsi, on veut parfois créer des objets dit &#8220;lazy&#8221;, littéralement &#8220;paresseux&#8221;, c&#8217;est à dire pas évalués tout de suite. C&#8217;est ce que fait Django dans le cadre de certaines chaînes de caractères traduites. En effet, en Django, il existe une fonction <code>lazy_gettex()</code> que l&#8217;on peut appliquer sur les chaînes à traduire. Mais elle ne retourne pas une string, car on ne connait pas encore la langue dans laquelle il faut traduire la chaîne : la langue dépend de l&#8217;utilisateur qui viendra demander la page Web en question. <code>lazy_gettex()</code> retourne un objet proxy, et quand, à l&#8217;appel de la page Web, on tente de manipuler cet objet comme une string pour l&#8217;afficher, le proxy va chercher la traduction, et retourne la bonne chaîne. Pour que ça marche, <strong>il faut que l&#8217;interface de l&#8217;objet lazy ressemble trait pour trait à celui d&#8217;une chaîne</strong>.</p>
<p>Dans d&#8217;autres cas on veut mettre un proxy pour gérer des permissions, et selon le niveau de permission, l&#8217;objet proxy donne accès ou non à l&#8217;objet derrière lui.</p>
<p>Le design pattern décorateur, le fameux <code>@truc</code> en Python, n&#8217;est jamais qu&#8217;un objet fonction qui fait proxy vers une autre fonction qu&#8217;on a enrobé.</p>
<p>Mais la raison majeur pour laquelle on va utiliser un objet proxy est le design pattern &#8220;adapter&#8221;.</p>
<h2>Ce n&#8217;est pas un chapeau, c&#8217;est un boa qui a avalé un éléphant</h2>
<p>En informatique, on aime bien les traitements généralistes.</p>
<p>Par exemple, imaginez cet objet qui dit si on a le droit de se bourrer la gueule :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">class</span> Videur<span style="color: black;">&#40;</span><span style="color: #008000;">object</span><span style="color: black;">&#41;</span>:
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> tu_peux_rentrer<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, personne<span style="color: black;">&#41;</span>:
        <span style="color: #483d8b;">&quot;&quot;&quot;
            Cette fonction n'est pas réaliste, puisque bien entendu une mineure
            à gros nichons rentrerait, et un arabe en short lacoste non,
            mais heureusement l'informatique est plus simple que notre société.
        &quot;&quot;&quot;</span>
        <span style="color: #ff7700;font-weight:bold;">return</span> personne.<span style="color: black;">age</span> <span style="color: #66cc66;">&gt;</span>= <span style="color: #ff4500;">18</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">class</span> Personne<span style="color: black;">&#40;</span><span style="color: #008000;">object</span><span style="color: black;">&#41;</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>, age<span style="color: black;">&#41;</span>:
        <span style="color: #008000;">self</span>.<span style="color: black;">age</span> = age</pre></div></div>

<p>Et tant que vous avez la main sur le système, tout va bien dans le meilleur des mondes :</p>

<div class="wp_syntax"><div 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;">random</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> clients = <span style="color: black;">&#91;</span>Personne<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;">12</span>, <span style="color: #ff4500;">65</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;">xrange</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;">0</span>, <span style="color: #ff4500;">100</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><span style="color: black;">&#93;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> videur = Videur<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #ff7700;font-weight:bold;">for</span> client <span style="color: #ff7700;font-weight:bold;">in</span> clients:
...     <span style="color: #ff7700;font-weight:bold;">if</span> videur.<span style="color: black;">tu_peux_rentrer</span><span style="color: black;">&#40;</span>client<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;Glouglou&quot;</span><span style="color: black;">&#41;</span>
...
<span style="color: black;">Glouglou</span>
Glouglou
Glouglou
Glouglou
Glouglou
...</pre></div></div>

<p>Mais malheureusement la vie n&#8217;est pas toujours pleine de licornes et de bisounours, et votre collègue, lui, il a codé une lib en C qui a extrait les clients d&#8217;un XML, et quand vous vous mappez directement dessus avec ctype, vous obtenez des clients comme ça:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">class</span> Client<span style="color: black;">&#40;</span><span style="color: #008000;">object</span><span style="color: black;">&#41;</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>, majeur<span style="color: black;">&#41;</span>:
        <span style="color: #008000;">self</span>.<span style="color: black;">majeur</span> = majeur</pre></div></div>

<p>Bon, vous vous dites que c&#8217;est pas grave. Après tout, c&#8217;est juste une condition à rajouter :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">class</span> Videur<span style="color: black;">&#40;</span><span style="color: #008000;">object</span><span style="color: black;">&#41;</span>:
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> tu_peux_rentrer<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, personne<span style="color: black;">&#41;</span>:
&nbsp;
        <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #008000;">hasattr</span><span style="color: black;">&#40;</span>personne, <span style="color: #483d8b;">'age'</span><span style="color: black;">&#41;</span>:
            <span style="color: #ff7700;font-weight:bold;">return</span> personne.<span style="color: black;">age</span> <span style="color: #66cc66;">&gt;</span>= <span style="color: #ff4500;">18</span>
&nbsp;
        <span style="color: #ff7700;font-weight:bold;">return</span> personne.<span style="color: black;">majeur</span></pre></div></div>

<p>Ouai mais votre commercial arrive avec un super contrat avec pillierdebar.com, et il faut s&#8217;interfacer avec leur API SOAP de 1997, dont la deserialisation vous retourne :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">class</span> Prospect<span style="color: black;">&#40;</span><span style="color: #008000;">object</span><span style="color: black;">&#41;</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: #dc143c;">datetime</span><span style="color: black;">&#41;</span>:
        <span style="color: #008000;">self</span>.<span style="color: black;">date_de_naissance</span> = <span style="color: #dc143c;">datetime</span></pre></div></div>

<p>Les connards. Ah les connards.</p>
<p>Mais bon, c&#8217;est pas grave, c&#8217;est juste une petite condition à rajouter.</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">datetime</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">class</span> Videur<span style="color: black;">&#40;</span><span style="color: #008000;">object</span><span style="color: black;">&#41;</span>:
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> tu_peux_rentrer<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, personne<span style="color: black;">&#41;</span>:
&nbsp;
        <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #008000;">hasattr</span><span style="color: black;">&#40;</span>personne, <span style="color: #483d8b;">'age'</span><span style="color: black;">&#41;</span>:
            <span style="color: #ff7700;font-weight:bold;">return</span> personne.<span style="color: black;">age</span> <span style="color: #66cc66;">&gt;</span>= <span style="color: #ff4500;">18</span>
&nbsp;
        <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #008000;">hasattr</span><span style="color: black;">&#40;</span>personne, <span style="color: #483d8b;">'date_de_naissance'</span><span style="color: black;">&#41;</span>:
            <span style="color: #808080; font-style: italic;"># TODO: prendre en compte les années bisextiles</span>
            <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: black;">&#40;</span><span style="color: #dc143c;">datetime</span>.<span style="color: #dc143c;">datetime</span>.<span style="color: black;">now</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span> - personne.<span style="color: black;">date_de_naissance</span><span style="color: black;">&#41;</span> / <span style="color: #ff4500;">365</span> <span style="color: #66cc66;">&gt;</span> <span style="color: #ff4500;">18</span>
&nbsp;
        <span style="color: #ff7700;font-weight:bold;">return</span> personne.<span style="color: black;">majeur</span></pre></div></div>

<p>Bon, vous allez enfin pouvoir soufll&#8230;. Ahhhh ! Votre boss appelle, il a oublié de vous dire, le stagiaire travaille aussi sur une feature, et a fait son propre objet <code>Prospect</code>, c&#8217;est comme l&#8217;objet <code>Client</code> mais pas pareil. Non on ne peut pas changer. Oui il a fait de la merde mais si on change tout son code pête. Il se barre demain. Il n&#8217;a pas fait de test. Démerde toi.</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">class</span> LeClient<span style="color: black;">&#40;</span><span style="color: #008000;">object</span><span style="color: black;">&#41;</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>, majeur_de_combien<span style="color: black;">&#41;</span>:
        <span style="color: #008000;">self</span>.__majeur_de_combien = majeur_de_combien
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> get_majeur_de_combien<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
        <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">self</span>.__majeur_de_combien</pre></div></div>

<p>A ce stade là, le code est tellement moche de toute façon, vous vous en branlez complètement. Vous allez rentrer jouer Left4Dead avec un mod qui transforme les zombies pour qu&#8217;ils aient la tête de votre patron. Le reste n&#8217;est que détail d&#8217;implémentation.</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">class</span> Videur<span style="color: black;">&#40;</span><span style="color: #008000;">object</span><span style="color: black;">&#41;</span>:
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> tu_peux_rentrer<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, personne<span style="color: black;">&#41;</span>:
&nbsp;
        <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #008000;">hasattr</span><span style="color: black;">&#40;</span>personne, <span style="color: #483d8b;">'age'</span><span style="color: black;">&#41;</span>:
            <span style="color: #ff7700;font-weight:bold;">return</span> personne.<span style="color: black;">age</span> <span style="color: #66cc66;">&gt;</span>= <span style="color: #ff4500;">18</span>
&nbsp;
        <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #008000;">hasattr</span><span style="color: black;">&#40;</span>personne, <span style="color: #483d8b;">'date_de_naissance'</span><span style="color: black;">&#41;</span>:
            <span style="color: #808080; font-style: italic;"># TODO: prendre en compte les années bisextiles</span>
            <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: black;">&#40;</span><span style="color: #dc143c;">datetime</span>.<span style="color: #dc143c;">datetime</span>.<span style="color: black;">now</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span> - personne.<span style="color: black;">date_de_naissance</span><span style="color: black;">&#41;</span> / <span style="color: #ff4500;">365</span> <span style="color: #66cc66;">&gt;</span> <span style="color: #ff4500;">18</span>
&nbsp;
        <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #008000;">hasattr</span><span style="color: black;">&#40;</span>personne, <span style="color: #483d8b;">'get_majeur_de_combien'</span><span style="color: black;">&#41;</span>:
            <span style="color: #808080; font-style: italic;"># retourne le nombre d'années après 18 ans ou -1. Don't ask...</span>
            <span style="color: #ff7700;font-weight:bold;">return</span> personne.<span style="color: black;">get_majeur_de_combien</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span> <span style="color: #66cc66;">&gt;</span> -<span style="color: #ff4500;">1</span>
&nbsp;
        <span style="color: #ff7700;font-weight:bold;">return</span> personne.<span style="color: black;">majeur</span></pre></div></div>

<p>Quelque moi(s) plus tard, les specs changent. Il faut maintenant pouvoir vérifier la carte d&#8217;identité des clients. Ou la carte de membre. Et garder l&#8217;ancien système compatible bien entendu. Ah, et il y a aussi des controleurs, c&#8217;est comme des videurs, mais qui doivent vérifier si les personnes dans le bar sont majeurs, sauf qu&#8217;il n&#8217;acceptent pas la carte de membre ou la date de naissance donnée à l&#8217;oral.</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">class</span> CarteDeMembre<span style="color: black;">&#40;</span><span style="color: #008000;">object</span><span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">pass</span>
&nbsp;
&nbsp;
<span style="color: #ff7700;font-weight:bold;">class</span> CarteIdentité<span style="color: black;">&#40;</span><span style="color: #008000;">object</span><span style="color: black;">&#41;</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>, date_de_naissance<span style="color: black;">&#41;</span>:
        <span style="color: #008000;">self</span>.<span style="color: black;">date_de_naissance</span> = date_de_naissance
&nbsp;
&nbsp;
<span style="color: #ff7700;font-weight:bold;">class</span> Client<span style="color: black;">&#40;</span><span style="color: #008000;">object</span><span style="color: black;">&#41;</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>, majeur=<span style="color: #008000;">None</span>, carte_identite=<span style="color: #008000;">None</span>, carte_membre=<span style="color: #008000;">None</span><span style="color: black;">&#41;</span>:
        <span style="color: #008000;">self</span>.<span style="color: black;">majeur</span> = majeur
        <span style="color: #008000;">self</span>.<span style="color: black;">carte_identite</span> = carte_identite
        <span style="color: #008000;">self</span>.<span style="color: black;">carte_membre</span> = <span style="color: #008000;">None</span>
&nbsp;
&nbsp;
<span style="color: #ff7700;font-weight:bold;">class</span> Videur<span style="color: black;">&#40;</span><span style="color: #008000;">object</span><span style="color: black;">&#41;</span>:
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> tu_peux_rentrer<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, personne<span style="color: black;">&#41;</span>:
&nbsp;
        <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #008000;">hasattr</span><span style="color: black;">&#40;</span>personne, <span style="color: #483d8b;">'age'</span><span style="color: black;">&#41;</span> <span style="color: #ff7700;font-weight:bold;">and</span> personne.<span style="color: black;">age</span> <span style="color: #ff7700;font-weight:bold;">is</span> <span style="color: #ff7700;font-weight:bold;">not</span> <span style="color: #008000;">None</span>:
            <span style="color: #ff7700;font-weight:bold;">return</span> personne.<span style="color: black;">age</span> <span style="color: #66cc66;">&gt;</span>= <span style="color: #ff4500;">18</span>
&nbsp;
        <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #008000;">hasattr</span><span style="color: black;">&#40;</span>personne, <span style="color: #483d8b;">'carte_membre'</span><span style="color: black;">&#41;</span>:
            <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">True</span>
&nbsp;
        <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #008000;">hasattr</span><span style="color: black;">&#40;</span>personne, <span style="color: #483d8b;">'carte_identite'</span><span style="color: black;">&#41;</span> <span style="color: #ff7700;font-weight:bold;">and</span> personne.<span style="color: black;">carte_identite</span> <span style="color: #ff7700;font-weight:bold;">is</span> <span style="color: #ff7700;font-weight:bold;">not</span> <span style="color: #008000;">None</span>:
            now = <span style="color: #dc143c;">datetime</span>.<span style="color: #dc143c;">datetime</span>.<span style="color: black;">now</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
            <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: black;">&#40;</span>now - personne.<span style="color: black;">carte_identite</span>.<span style="color: black;">date_de_naissance</span><span style="color: black;">&#41;</span> / <span style="color: #ff4500;">365</span> <span style="color: #66cc66;">&gt;</span> <span style="color: #ff4500;">18</span>
&nbsp;
        <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #008000;">hasattr</span><span style="color: black;">&#40;</span>personne, <span style="color: #483d8b;">'date_de_naissance'</span><span style="color: black;">&#41;</span>:
            <span style="color: #808080; font-style: italic;"># TODO: prendre en compte les années bisextiles</span>
            <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: black;">&#40;</span><span style="color: #dc143c;">datetime</span>.<span style="color: #dc143c;">datetime</span>.<span style="color: black;">now</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span> - personne.<span style="color: black;">date_de_naissance</span><span style="color: black;">&#41;</span> / <span style="color: #ff4500;">365</span> <span style="color: #66cc66;">&gt;</span> <span style="color: #ff4500;">18</span>
&nbsp;
        <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #008000;">hasattr</span><span style="color: black;">&#40;</span>personne, <span style="color: #483d8b;">'get_majeur_de_combien'</span><span style="color: black;">&#41;</span>:
            <span style="color: #808080; font-style: italic;"># retourne le nombre d'années après 18 ans ou -1. Don't ask...</span>
            <span style="color: #ff7700;font-weight:bold;">return</span> personne.<span style="color: black;">get_majeur_de_combien</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span> <span style="color: #66cc66;">&gt;</span> -<span style="color: #ff4500;">1</span>
&nbsp;
        <span style="color: #ff7700;font-weight:bold;">return</span> personne.<span style="color: black;">majeur</span>
&nbsp;
&nbsp;
<span style="color: #ff7700;font-weight:bold;">class</span> Controleur<span style="color: black;">&#40;</span><span style="color: #008000;">object</span><span style="color: black;">&#41;</span>:
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> est_autorise<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, personne<span style="color: black;">&#41;</span>:
&nbsp;
        <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #008000;">hasattr</span><span style="color: black;">&#40;</span>personne, <span style="color: #483d8b;">'age'</span><span style="color: black;">&#41;</span> <span style="color: #ff7700;font-weight:bold;">and</span> personne.<span style="color: black;">age</span> <span style="color: #ff7700;font-weight:bold;">is</span> <span style="color: #ff7700;font-weight:bold;">not</span> <span style="color: #008000;">None</span>:
            <span style="color: #ff7700;font-weight:bold;">return</span> personne.<span style="color: black;">age</span> <span style="color: #66cc66;">&gt;</span>= <span style="color: #ff4500;">18</span>
&nbsp;
        <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #008000;">hasattr</span><span style="color: black;">&#40;</span>personne, <span style="color: #483d8b;">'carte_identite'</span><span style="color: black;">&#41;</span> <span style="color: #ff7700;font-weight:bold;">and</span> personne.<span style="color: black;">carte_identite</span> <span style="color: #ff7700;font-weight:bold;">is</span> <span style="color: #ff7700;font-weight:bold;">not</span> <span style="color: #008000;">None</span>:
            now = <span style="color: #dc143c;">datetime</span>.<span style="color: #dc143c;">datetime</span>.<span style="color: black;">now</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
            <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: black;">&#40;</span>now - personne.<span style="color: black;">carte_identite</span>.<span style="color: black;">date_de_naissance</span><span style="color: black;">&#41;</span> / <span style="color: #ff4500;">365</span> <span style="color: #66cc66;">&gt;</span> <span style="color: #ff4500;">18</span>
&nbsp;
        <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #008000;">hasattr</span><span style="color: black;">&#40;</span>personne, <span style="color: #483d8b;">'date_de_naissance'</span><span style="color: black;">&#41;</span>:
            <span style="color: #808080; font-style: italic;"># TODO: prendre en compte les années bisextiles</span>
            <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: black;">&#40;</span><span style="color: #dc143c;">datetime</span>.<span style="color: #dc143c;">datetime</span>.<span style="color: black;">now</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span> - personne.<span style="color: black;">date_de_naissance</span><span style="color: black;">&#41;</span> / <span style="color: #ff4500;">365</span> <span style="color: #66cc66;">&gt;</span> <span style="color: #ff4500;">18</span>
&nbsp;
        <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #008000;">hasattr</span><span style="color: black;">&#40;</span>personne, <span style="color: #483d8b;">'get_majeur_de_combien'</span><span style="color: black;">&#41;</span>:
            <span style="color: #808080; font-style: italic;"># retourne le nombre d'années après 18 ans ou -1. Don't ask...</span>
            <span style="color: #ff7700;font-weight:bold;">return</span> personne.<span style="color: black;">get_majeur_de_combien</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span> <span style="color: #66cc66;">&gt;</span> -<span style="color: #ff4500;">1</span>
&nbsp;
        <span style="color: #ff7700;font-weight:bold;">return</span> personne.<span style="color: black;">majeur</span></pre></div></div>

<p>Bon, là c&#8217;est la merde. Vous le sentez, demain il va y avoir un portail électronique qui check uniquement les cartes de membres. Quand il va falloir faire une modif quelque part, ça va être galère. La maintenance va être un enfer. Le debuggage, bien relou. Il faut trouver un moyen de faire plus propre.</p>
<p>C&#8217;est ici qu&#8217;entre en jeu le pattern &#8220;adapter&#8221;. Un adapter, c&#8217;est comme les adaptateurs pour prises, mais pour les objets. C&#8217;est un proxy qu&#8217;on met devant pour que la prise ressemble à une autre.</p>
<p>Dans le domaine du code, ça veut dire qu&#8217;on va enrober chaque objet dans un autre pour qu&#8217;ils aient tous la même interface. Le traitement du coup sera de nouveau très simple, et la complexité sera répartie dans les adapters.</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">&nbsp;
<span style="color: #808080; font-style: italic;"># on met le code commun dans un parent abstrait, notamment le check pour</span>
<span style="color: #808080; font-style: italic;"># savoir si un adapter convient a un objet donné</span>
<span style="color: #ff7700;font-weight:bold;">class</span> Adapteur<span style="color: black;">&#40;</span><span style="color: #008000;">object</span><span style="color: black;">&#41;</span>:
&nbsp;
    cls = <span style="color: #008000;">None</span>
&nbsp;
    <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>, objet<span style="color: black;">&#41;</span>:
        <span style="color: #008000;">self</span>.<span style="color: black;">objet</span> = objet
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> peut_adapter<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, objet<span style="color: black;">&#41;</span>:
        <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">self</span>.<span style="color: black;">cls</span> == <span style="color: #008000;">type</span><span style="color: black;">&#40;</span>objet<span style="color: black;">&#41;</span>
&nbsp;
&nbsp;
<span style="color: #808080; font-style: italic;"># un adapter, c'est juste un objet proxy qui arrondit les angles</span>
<span style="color: #ff7700;font-weight:bold;">class</span> PersonneAdapteur<span style="color: black;">&#40;</span>Adapteur<span style="color: black;">&#41;</span>:
&nbsp;
    cls = Personne
&nbsp;
    <span style="color: #808080; font-style: italic;"># on va réduire la complexité en faisant en sorte que tous les checks</span>
    <span style="color: #808080; font-style: italic;"># soient cachés derrière une simple property</span>
    @<span style="color: #008000;">property</span>
    <span style="color: #ff7700;font-weight:bold;">def</span> majeur<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
        <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">self</span>.<span style="color: black;">objet</span> <span style="color: #66cc66;">&gt;</span>= <span style="color: #ff4500;">18</span>
&nbsp;
&nbsp;
<span style="color: #ff7700;font-weight:bold;">class</span> ProspectAdapteur<span style="color: black;">&#40;</span>Adapteur<span style="color: black;">&#41;</span>:
&nbsp;
    cls = Prospect
&nbsp;
    @<span style="color: #008000;">property</span>
    <span style="color: #ff7700;font-weight:bold;">def</span> majeur<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
        <span style="color: #808080; font-style: italic;"># TODO: prendre en compte les années bisextiles</span>
        <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: black;">&#40;</span><span style="color: #dc143c;">datetime</span>.<span style="color: #dc143c;">datetime</span>.<span style="color: black;">now</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span> - <span style="color: #008000;">self</span>.<span style="color: black;">objet</span>.<span style="color: black;">date_de_naissance</span><span style="color: black;">&#41;</span> / <span style="color: #ff4500;">365</span> <span style="color: #66cc66;">&gt;</span> <span style="color: #ff4500;">18</span>
&nbsp;
&nbsp;
<span style="color: #ff7700;font-weight:bold;">class</span> LeClientAdapteur<span style="color: black;">&#40;</span>Adapteur<span style="color: black;">&#41;</span>:
&nbsp;
    cls = LeClient
&nbsp;
    @<span style="color: #008000;">property</span>
    <span style="color: #ff7700;font-weight:bold;">def</span> majeur<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
        <span style="color: #808080; font-style: italic;"># retourne le nombre d'années après 18 ans ou -1. Don't ask...</span>
        <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">self</span>.<span style="color: black;">objet</span>.<span style="color: black;">get_majeur_de_combien</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span> <span style="color: #66cc66;">&gt;</span> -<span style="color: #ff4500;">1</span>
&nbsp;
&nbsp;
<span style="color: #ff7700;font-weight:bold;">class</span> ClientAdapteur<span style="color: black;">&#40;</span>Adapteur<span style="color: black;">&#41;</span>:
&nbsp;
    cls = Client
&nbsp;
    <span style="color: #808080; font-style: italic;"># les adapteurs peuvent être configurables</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>, objet, accepte_carte_membre=<span style="color: #008000;">True</span><span style="color: black;">&#41;</span>:
        <span style="color: #008000;">self</span>.<span style="color: black;">objet</span> = objet
        <span style="color: #008000;">self</span>.<span style="color: black;">accepte_carte_membre</span> = accepte_carte_membre
&nbsp;
&nbsp;
    @<span style="color: #008000;">property</span>
    <span style="color: #ff7700;font-weight:bold;">def</span> majeur<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
&nbsp;
        <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #008000;">self</span>.<span style="color: black;">accepte_carte_membre</span> <span style="color: #ff7700;font-weight:bold;">and</span> <span style="color: #008000;">self</span>.<span style="color: black;">objet</span>.<span style="color: black;">carte_membre</span> <span style="color: #ff7700;font-weight:bold;">is</span> <span style="color: #ff7700;font-weight:bold;">not</span> <span style="color: #008000;">None</span>:
            <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">True</span>
&nbsp;
        <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #008000;">self</span>.<span style="color: black;">objet</span>.<span style="color: black;">majeur</span>:
            <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">True</span>
&nbsp;
        <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #008000;">self</span>.<span style="color: #008000;">object</span>.<span style="color: black;">carte_identite</span> <span style="color: #ff7700;font-weight:bold;">is</span> <span style="color: #ff7700;font-weight:bold;">not</span> <span style="color: #008000;">None</span>:
            now = <span style="color: #dc143c;">datetime</span>.<span style="color: #dc143c;">datetime</span>.<span style="color: black;">now</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
            <span style="color: #808080; font-style: italic;"># TODO: prendre en compte les années bisextiles</span>
            <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: black;">&#40;</span>now - personne.<span style="color: black;">carte_identite</span>.<span style="color: black;">date_de_naissance</span><span style="color: black;">&#41;</span> / <span style="color: #ff4500;">365</span> <span style="color: #66cc66;">&gt;</span> <span style="color: #ff4500;">18</span>
&nbsp;
        <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">False</span></pre></div></div>

<p>Le controleur et le videur deviennent du coup beaucoup plus simples, maintenant que la logique est normalisée :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">class</span> VerificateurDeMajorite<span style="color: black;">&#40;</span><span style="color: #008000;">object</span><span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">def</span> check_majorite<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, personne<span style="color: black;">&#41;</span>:
        <span style="color: #ff7700;font-weight:bold;">for</span> adapteur <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">self</span>.<span style="color: black;">adapteurs</span>:
            <span style="color: #ff7700;font-weight:bold;">if</span> adapteur.<span style="color: black;">peut_adapter</span><span style="color: black;">&#40;</span>personne<span style="color: black;">&#41;</span>:
                <span style="color: #ff7700;font-weight:bold;">return</span> adapteur<span style="color: black;">&#40;</span>personne<span style="color: black;">&#41;</span>.<span style="color: black;">majeur</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># du coup un vérificateur, c'est très déclaratif</span>
<span style="color: #ff7700;font-weight:bold;">class</span> Videur<span style="color: black;">&#40;</span>VerificateurDeMajorite<span style="color: black;">&#41;</span>:
&nbsp;
    adapteurs = <span style="color: black;">&#40;</span>
        PersonneAdapteur<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>,
        ClientAdapteur<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>,
        ProspectAdapteur<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>,
        LeClientAdapteur<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>,
    <span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> tu_peux_rentrer<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, personne<span style="color: black;">&#41;</span>:
        <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">self</span>.<span style="color: black;">check_majorite</span><span style="color: black;">&#40;</span>personne<span style="color: black;">&#41;</span>
&nbsp;
&nbsp;
<span style="color: #ff7700;font-weight:bold;">class</span> Controleur<span style="color: black;">&#40;</span>VerificateurDeMajorite<span style="color: black;">&#41;</span>:
&nbsp;
    adapteurs = <span style="color: black;">&#40;</span>
        PersonneAdapteur<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>,
        ClientAdapteur<span style="color: black;">&#40;</span>accepte_carte_membre=<span style="color: #008000;">False</span><span style="color: black;">&#41;</span>,
        <span style="color: #808080; font-style: italic;"># ProspectAdapteur()</span>
        LeClientAdapteur<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>,
    <span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> est_autorise<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, personne<span style="color: black;">&#41;</span>:
        <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">self</span>.<span style="color: black;">check_majorite</span><span style="color: black;">&#40;</span>personne<span style="color: black;">&#41;</span></pre></div></div>

<p>Si il faut ajouter un autre format de client, il suffit de coder un adapteur. Si il faut ajouter une autre classe de vérification, il suffit de lui donner les bons adapteurs.</p>
<p>Et le traitement est aussi simple, car si vous avez une liste qui contient plein de clients différents :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">&gt;&gt;&gt;</span> clients = <span style="color: black;">&#91;</span>Client<span style="color: black;">&#40;</span>majeur=<span style="color: #008000;">True</span><span style="color: black;">&#41;</span>, Client<span style="color: black;">&#40;</span>carte_de_membre=CarteDeMembre<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>, Client<span style="color: black;">&#40;</span>carte_identite=CarteIdentité<span style="color: black;">&#40;</span><span style="color: #dc143c;">datetime</span>.<span style="color: #dc143c;">datetime</span>.<span style="color: black;">now</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>, LeClient<span style="color: black;">&#40;</span>-<span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span>, Personne<span style="color: black;">&#40;</span>age=<span style="color: #ff4500;">16</span><span style="color: black;">&#41;</span>...<span style="color: black;">&#93;</span></pre></div></div>

<p>Vous pouvez quand même vérifier tout ça sans y réfléchir:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">&gt;&gt;&gt;</span> videur = Videur<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #ff7700;font-weight:bold;">for</span> client <span style="color: #ff7700;font-weight:bold;">in</span> clients:
...     <span style="color: #ff7700;font-weight:bold;">if</span> videur.<span style="color: black;">tu_peux_rentrer</span><span style="color: black;">&#40;</span>client<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;Glouglou&quot;</span><span style="color: black;">&#41;</span>
...
<span style="color: black;">Glouglou</span>
Glouglou
...
&nbsp;
<span style="color: #66cc66;">&gt;&gt;&gt;</span> controlleur = Controleur<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #ff7700;font-weight:bold;">for</span> client <span style="color: #ff7700;font-weight:bold;">in</span> clients:
...     <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #ff7700;font-weight:bold;">not</span> controlleur.<span style="color: black;">est_autorise</span><span style="color: black;">&#40;</span>client<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;Ahhhh !&quot;</span><span style="color: black;">&#41;</span>
...
<span style="color: black;">Ahhhh</span> <span style="color: #66cc66;">!</span>
Ahhhh <span style="color: #66cc66;">!</span>
...</pre></div></div>

<p>Dans un cas comme celui de notre exemple, l&#8217;adapter est un peu overkill, on s&#8217;en tirerait aussi bien avec une liste de fonctions, et le code serait plus léger et lisible.</p>
<p> Mais quand les objets et la logique deviennent très complexes, tout ramener à une interface commune permet de simplifier énormément le code.</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=7112&amp;md5=dd69aed35d7a04dab21ab6d6601e104e" title="Flattr" target="_blank"><img src="media/fc229d00.flattr-badge-large.png" data-original-source="http://sametmax.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>


feed_id: http://sametmax.com/?p=7122
title: Ecrire un code pour les autres en Python
uri: Ecrire-un-code-pour-les-autres-en-Python
url: http://sametmax.com/ecrire-un-code-pour-les-autres-en-python/
content:
<p>Cet article s&#8217;adresse à des développeurs qui commencent à être bien dans leurs chaussettes en Python et qui se sentent de relever le défi d&#8217;écrire du code pour d&#8217;autres personnes.</p>
<p>Car quand vous allez publier du code, un script, une lib voire, Dieu ait pitié de vous, un framework, les gens qui vont les utiliser vont avoir des besoins auxquels vous n&#8217;aviez pas pensé. Or, ils ne voudront pas modifier votre code. L&#8217;interêt d&#8217;utiliser le code d&#8217;un autre, c&#8217;est justement de s&#8217;éviter la maintenance. Ils voudront aussi prendre en main rapidement votre outil pour faire des choses simples sans avoir à tout comprendre.</p>
<p>Ainsi, il va vous falloir intégrer divers moyens d&#8217;étendre les fonctionnalités de votre code, afin que les autres dev puissent l&#8217;utiliser dans le cadre de leurs besoins.</p>
<p>Nous allons donc construire un projet bidon : une barre de progression en ASCII dont la sortie va ressembler à ceci :</p>
<p>Starting [=========================================     ] 93%</p>
<p>L&#8217;idée est de pouvoir l&#8217;utiliser ainsi :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">    <span style="color: #ff7700;font-weight:bold;">with</span> ProgressBar<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span> <span style="color: #ff7700;font-weight:bold;">as</span> pb:
        <span style="color: #ff7700;font-weight:bold;">for</span> progres <span style="color: #ff7700;font-weight:bold;">in</span> faire_un_truc<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
            pb.<span style="color: black;">progress</span> = progres</pre></div></div>

<p>Nous allons le proposer ce projet sous forme de classe importable, et nous allons voir plusieurs manières de rendre ce code facile à prendre en main, configurable et extensible :</p>
<ul>
<li>Paramètres, avec un ordre intelligent et des valeurs par défaut saines.</li>
<li>Templating de l&#8217;ouput.</li>
<li>Methodes pouvant être écrasée par héritage.</li>
<li>Getter and setter (ici via des propriétés)</li>
<li>Exposition intelligente des attributs de la classe.</li>
<li>Callbacks et passage réfléchi de paramètres à ceux-ci.</li>
</ul>
<p>J&#8217;aurais pu ajouter l&#8217;injection de dépendance, mais j&#8217;ai déjà traité ce sujet dans un autre article, et je ne voulais pas charger celui-ci. Il est déjà bien gras.</p>
<p>J&#8217;ai aussi volontairement omis la docstring et les comments. Écrire une bonne doc est un article à part entière.</p>
<p>Pré-requis : être parfaitement à l&#8217;aise avec le <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/">POO</a> et les références, comprendre le principe des context managers, avoir pigé les <a href="http://sametmax.com/quest-ce-quun-callback/">callbacks</a>.</p>
<p>Et roulez jeunesse !</p>

<!-- iframe plugin v:2.3 - wordpress.org/extend/plugins/iframe/ -->
<iframe width="560" height="315" src="//www.youtube.com/embed/zoF7qxapnSA" frameborder="0" scrolling="no" class="iframe-class"></iframe>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #808080; font-style: italic;"># -*- coding: utf-8 -*-</span>
&nbsp;
&nbsp;
&nbsp;
<span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">sys</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">from</span> io <span style="color: #ff7700;font-weight:bold;">import</span> IOBase
&nbsp;
&nbsp;
<span style="color: #808080; font-style: italic;"># On hérite d'IOBase pour permettre le détournement de stdout. Voir plus bas.</span>
<span style="color: #ff7700;font-weight:bold;">class</span> ProgressBar<span style="color: black;">&#40;</span>IOBase<span style="color: black;">&#41;</span>:
&nbsp;
&nbsp;
    <span style="color: #808080; font-style: italic;"># On met les paramètres par ordre de fréquence d'utilisation. Il est</span>
    <span style="color: #808080; font-style: italic;"># plus probable que les programmeurs changent le total que la sortie</span>
    <span style="color: #808080; font-style: italic;"># du programme.</span>
    <span style="color: #808080; font-style: italic;"># Mettre des valeurs par défaut saines permet à l'utilisateur de faire</span>
    <span style="color: #808080; font-style: italic;"># des essais sans trop regarder la doc. Par ailleurs, des valeurs par</span>
    <span style="color: #808080; font-style: italic;"># défaut servent de documentation en soit, et apparaitront si help()</span>
    <span style="color: #808080; font-style: italic;"># est appelé.</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>, total=<span style="color: #ff4500;">100</span>,  percent_per_sign=<span style="color: #ff4500;">1</span>,
                 progress_sign=<span style="color: #483d8b;">'='</span>, callbacks=<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>,
                 template=<span style="color: #483d8b;">'Starting [{bar}] {progress}%'</span>,
                 output=<span style="color: #dc143c;">sys</span>.<span style="color: black;">stdout</span>, intercept_stdout=<span style="color: #008000;">True</span><span style="color: black;">&#41;</span>:
&nbsp;
        <span style="color: #808080; font-style: italic;"># Par défaut le total est 100, afin que l'utilisateur passe un</span>
        <span style="color: #808080; font-style: italic;"># pourcentage, ce qui est le plus naturel. Néanmoins, si il souhaite</span>
        <span style="color: #808080; font-style: italic;"># s'affranchir de calculs, on lui permet de passer une autre valeur</span>
        <span style="color: #808080; font-style: italic;"># qui sera ramenée à un pourcentage automatiquement à l'affichage</span>
        <span style="color: #808080; font-style: italic;"># de toute façon.</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">total</span> = total
&nbsp;
        <span style="color: #808080; font-style: italic;"># Customisation de base : changer le symbole de progrès. Par défaut</span>
        <span style="color: #808080; font-style: italic;"># un égal, mais certains aiment les ., les - ou autre.</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">progress_sign</span> = progress_sign
&nbsp;
        <span style="color: #808080; font-style: italic;"># Idem, si la personne veut une barre plus ou moins longue.</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">percent_per_sign</span> = percent_per_sign
&nbsp;
        <span style="color: #808080; font-style: italic;"># la longueur de la barre de progression</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">bar_len</span> = <span style="color: #ff4500;">100</span> / percent_per_sign <span style="color: #66cc66;">*</span> <span style="color: #008000;">len</span><span style="color: black;">&#40;</span>progress_sign<span style="color: black;">&#41;</span>
&nbsp;
        <span style="color: #808080; font-style: italic;"># Le formatage de la progress bar se fait à l'aide d'une chaîne</span>
        <span style="color: #808080; font-style: italic;"># ordinaire qui sert de template (avec le langage de formatage de Python)</span>
        <span style="color: #808080; font-style: italic;"># et peut facilement être changée pour obtenir plus de contrôle</span>
        <span style="color: #808080; font-style: italic;"># sur l'aspect de la bar.</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">template</span> = template
&nbsp;
        <span style="color: #808080; font-style: italic;"># On peut aussi passer un tuple de fonctions qui permettent de réagir</span>
        <span style="color: #808080; font-style: italic;"># à chaque fois que le progrès change. On utilise nous-même notre</span>
        <span style="color: #808080; font-style: italic;"># système de callback pour que la methode print_progress() soit</span>
        <span style="color: #808080; font-style: italic;"># appelée à chaque fois, mettant à jour l'affichage de la bar.</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">callbacks</span> = callbacks + <span style="color: black;">&#40;</span><span style="color: #008000;">self</span>.<span style="color: black;">print_progress</span>,<span style="color: black;">&#41;</span>
&nbsp;
        <span style="color: #808080; font-style: italic;"># Initialisation de 3 variables à vide. 'buffer' va contenir</span>
        <span style="color: #808080; font-style: italic;"># tout ce qui va être écrit avec write() pour éviter de perturber</span>
        <span style="color: #808080; font-style: italic;"># l'affichage de la bar, et '_progress' va contenir le progrès, mais</span>
        <span style="color: #808080; font-style: italic;"># le '_' signale que c'est une variable à usage interne. Nous allons</span>
        <span style="color: #808080; font-style: italic;"># en effet l'enrober dans une propriété. Enfin cursor_shift est</span>
        <span style="color: #808080; font-style: italic;"># le nombre de caractères à effacer pour redessiner la bar à chaque</span>
        <span style="color: #808080; font-style: italic;"># mise à jour.</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">buffer</span> = <span style="color: #483d8b;">''</span>
        <span style="color: #008000;">self</span>._progress = <span style="color: #ff4500;">0</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">cursor_shift</span> = <span style="color: #ff4500;">0</span>
&nbsp;
        <span style="color: #808080; font-style: italic;"># Par défaut, on s'attend à ce que l'utilisateur affiche cette</span>
        <span style="color: #808080; font-style: italic;"># bar directement dans le terminal, sur la sortie standard. Mais</span>
        <span style="color: #808080; font-style: italic;"># il peut vouloir déporter l'affichage ailleurs (par exemple stderr).</span>
        <span style="color: #808080; font-style: italic;"># Pour cette raison, on permet de passer le stream sur lequel</span>
        <span style="color: #808080; font-style: italic;"># l'utilisateur va écrire, même si par défaut on prend sys.stdout,</span>
        <span style="color: #808080; font-style: italic;"># donc la sortie standard.</span>
        <span style="color: #808080; font-style: italic;"># Si l'utilisateur ne souhaite rien de tout cela, il peut également</span>
        <span style="color: #808080; font-style: italic;"># retirer 'self.print_progress' de la liste des callbacks puisque</span>
        <span style="color: #808080; font-style: italic;"># l'attribut est public.</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">out</span> = output
&nbsp;
        <span style="color: #808080; font-style: italic;"># Comme on utilise la sortie standard par défaut, la barre peut</span>
        <span style="color: #808080; font-style: italic;"># facilement être cassée par un autre code écrivant aussi sur la sortie</span>
        <span style="color: #808080; font-style: italic;"># standard. Puisqu'un débutant ne comprendra pas rour se suite ce qui se</span>
        <span style="color: #808080; font-style: italic;"># passe, par défaut on va intercepter stdout et mettre tout ce qui est</span>
        <span style="color: #808080; font-style: italic;"># écrit dessus dans un buffer. Si jamais il y a des prints fait durant</span>
        <span style="color: #808080; font-style: italic;"># l'affichage, il seront cachés, et stockés. Ce comportement n'est pas</span>
        <span style="color: #808080; font-style: italic;"># forcément désirable, et peut donc être désactivé par un paramètre pour</span>
        <span style="color: #808080; font-style: italic;"># l'utilisateur qui sait ce qu'il fait notamment dans le cadre</span>
        <span style="color: #808080; font-style: italic;"># d'utilisation des threads.</span>
        <span style="color: #008000;">self</span>._intercept_stdout = intercept_stdout <span style="color: #ff7700;font-weight:bold;">and</span> <span style="color: #008000;">self</span>.<span style="color: black;">out</span> == <span style="color: #dc143c;">sys</span>.<span style="color: black;">stdout</span>
        <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #008000;">self</span>._intercept_stdout:
            <span style="color: #808080; font-style: italic;"># L'interception de la sortie standard se fait en remplaçant</span>
            <span style="color: #808080; font-style: italic;"># sys.stdout par soi-même. C'est pour cette raison que ProgressBar</span>
            <span style="color: #808080; font-style: italic;"># hérite de IOBase. En effet, de cette manière, on possède</span>
            <span style="color: #808080; font-style: italic;"># l'interface d'un objet stream et tout écriture sur 'self' semblera</span>
            <span style="color: #808080; font-style: italic;"># fonctionner comme sur sys.stdout. Cela permet de faire des prints</span>
            <span style="color: #808080; font-style: italic;"># ou de lancer un shell et d'utiliser la barre, bien que</span>
            <span style="color: #808080; font-style: italic;"># dans un shell cela monopolisera le prompt.</span>
            <span style="color: #dc143c;">sys</span>.<span style="color: black;">stdout</span> = <span style="color: #008000;">self</span>
&nbsp;
&nbsp;
    <span style="color: #808080; font-style: italic;"># Afficher la barre à la création de l'objet retire de la flexibilité à</span>
    <span style="color: #808080; font-style: italic;"># l'utilisateur qui peut vouloir le créer d'un côté, le stocker, et</span>
    <span style="color: #808080; font-style: italic;"># démarrer l'affichage plus tard. L'affichage est donc conditionné</span>
    <span style="color: #808080; font-style: italic;"># par cette méthode.</span>
    <span style="color: #ff7700;font-weight:bold;">def</span> show<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
        bar = <span style="color: #008000;">self</span>.<span style="color: black;">format</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">out</span>.<span style="color: black;">write</span><span style="color: black;">&#40;</span>bar<span style="color: black;">&#41;</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">cursor_shift</span> = <span style="color: #008000;">len</span><span style="color: black;">&#40;</span>bar<span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">self</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># Comme le plus souvent on voudra tout de même afficher la barre juste après</span>
    <span style="color: #808080; font-style: italic;"># la création, on transforme cette classe en context manager. Pour cela on</span>
    <span style="color: #808080; font-style: italic;"># créer un alias de la method show() qu'on appelle __enter__, puisque tout</span>
    <span style="color: #808080; font-style: italic;"># objet qui a une méthode nommée __enter__ peut être utilisé comme context</span>
    <span style="color: #808080; font-style: italic;"># manager. Si vous ne vous souvenez pas de ce que c'est, il y a un article</span>
    <span style="color: #808080; font-style: italic;"># sur le blog à ce sujet. Mais en résumé, ce sont les objets utilisables</span>
    <span style="color: #808080; font-style: italic;"># avec &quot;with&quot;.</span>
    <span style="color: #808080; font-style: italic;"># Notez qu'on ne fait pas __enter__ = show, ce qui serait un moyen plus</span>
    <span style="color: #808080; font-style: italic;"># court d'aliaser, car il empêcherait __enter__ d'appeler le bon show()</span>
    <span style="color: #808080; font-style: italic;"># en cas d'héritage, si show() est écrasé.</span>
    <span style="color: #ff7700;font-weight:bold;">def</span> __enter__<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
        <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">self</span>.<span style="color: black;">show</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
&nbsp;
    <span style="color: #808080; font-style: italic;"># Une petit méthode de nettoyage, qui ici va simplement remettre sys.stdout</span>
    <span style="color: #808080; font-style: italic;"># à sa place.</span>
    <span style="color: #ff7700;font-weight:bold;">def</span> stop<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, <span style="color: #66cc66;">*</span>args, <span style="color: #66cc66;">**</span>kwargs<span style="color: black;">&#41;</span>:
        <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #008000;">self</span>._intercept_stdout:
            <span style="color: #dc143c;">sys</span>.<span style="color: black;">stdout</span> = <span style="color: #008000;">self</span>.<span style="color: black;">out</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># Même topo, on alias stop en __exit__ pour avoir la sortie du context</span>
    <span style="color: #808080; font-style: italic;"># manager. On a pas appelé directement ces méthodes __enter__ et __exit__</span>
    <span style="color: #808080; font-style: italic;"># car l'utilisateur peut vouloir les appeler manuellement.</span>
    <span style="color: #ff7700;font-weight:bold;">def</span> __exit__<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, <span style="color: #66cc66;">*</span>args, <span style="color: #66cc66;">**</span>kwargs<span style="color: black;">&#41;</span>:
        <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">self</span>.<span style="color: black;">stop</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
&nbsp;
    <span style="color: #808080; font-style: italic;"># Une simple propriété qui donne accès au progres en lecture...</span>
    @<span style="color: #008000;">property</span>
    <span style="color: #ff7700;font-weight:bold;">def</span> progress<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
        <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">self</span>._progress
&nbsp;
&nbsp;
    <span style="color: #808080; font-style: italic;"># ... et en écriture. La différence étant qu'à l'écriture, on vérifie</span>
    <span style="color: #808080; font-style: italic;"># que la valeur est bien comprise entre 0 et le total. On appelle aussi</span>
    <span style="color: #808080; font-style: italic;"># les callbacks, et donc l'affichage se mettra à jour.</span>
    @progress.<span style="color: black;">setter</span>
    <span style="color: #ff7700;font-weight:bold;">def</span> progress<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, value<span style="color: black;">&#41;</span>:
&nbsp;
        <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #ff7700;font-weight:bold;">not</span> <span style="color: #ff4500;">0</span> <span style="color: #66cc66;">&lt;</span>= value <span style="color: #66cc66;">&lt;</span>= <span style="color: #008000;">self</span>.<span style="color: black;">total</span>:
            <span style="color: #ff7700;font-weight:bold;">raise</span> <span style="color: #008000;">ValueError</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;'value' is %s and should be set between 0 &quot;</span>
                             <span style="color: #483d8b;">&quot;and 'total' (%s)&quot;</span> <span style="color: #66cc66;">%</span> <span style="color: black;">&#40;</span>value, <span style="color: #008000;">self</span>.<span style="color: black;">total</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
&nbsp;
        <span style="color: #808080; font-style: italic;"># On le fait avant car les callbacks doivent être appelés</span>
        <span style="color: #808080; font-style: italic;"># avec un état propre.</span>
        previous_progress = <span style="color: #008000;">self</span>._progress
        <span style="color: #008000;">self</span>._progress = value
&nbsp;
        <span style="color: #808080; font-style: italic;"># Ce que l'on va passer en paramètres aux callbacks est un choix</span>
        <span style="color: #808080; font-style: italic;"># important. Déjà en premier paramètre, on passe self. Ainsi le callback</span>
        <span style="color: #808080; font-style: italic;"># aura accès à presque tout, et on est certain qu'il ne se trouvera</span>
        <span style="color: #808080; font-style: italic;"># pas dépourvu d'informations. Ensuite on passe le progrès. Normalement</span>
        <span style="color: #808080; font-style: italic;"># il peut le récupérer à travers self.progress, mais comme on sait</span>
        <span style="color: #808080; font-style: italic;"># que c'est une information très utilisée, on la passe par politesse,</span>
        <span style="color: #808080; font-style: italic;"># pour faciliter la vie de l'utilisateur. Enfin, une information qu'il</span>
        <span style="color: #808080; font-style: italic;"># ne pourrait pas avoir autrement est le progrès précédent. Bien que</span>
        <span style="color: #808080; font-style: italic;"># nous ne l'utilisons pas dans notre callback, on peut imaginer que</span>
        <span style="color: #808080; font-style: italic;"># c'est le genre d'info qui peut être utile, et qui ne peut être trouvée</span>
        <span style="color: #808080; font-style: italic;"># dans self.</span>
        <span style="color: #ff7700;font-weight:bold;">for</span> callback <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">self</span>.<span style="color: black;">callbacks</span>:
            callback<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, <span style="color: #008000;">self</span>._progress, previous_progress<span style="color: black;">&#41;</span>
&nbsp;
        <span style="color: #808080; font-style: italic;"># Si on arrive au bout, on appelle stop() automatiquement. Stop()</span>
        <span style="color: #808080; font-style: italic;"># étant idempotente, ce n'est pas grave si elle est appelée plusieurs</span>
        <span style="color: #808080; font-style: italic;"># fois.</span>
        <span style="color: #ff7700;font-weight:bold;">if</span> value == <span style="color: #008000;">self</span>.<span style="color: black;">total</span>:
            <span style="color: #008000;">self</span>.<span style="color: black;">stop</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># Un cas intéressant : pourquoi on ne fait pas self.template directement au</span>
    <span style="color: #808080; font-style: italic;"># lieu de créer une property à vide ? Tout simplement parce qu'un template</span>
    <span style="color: #808080; font-style: italic;"># est typiquement quelque chose que quelqu'un peut vouloir créer</span>
    <span style="color: #808080; font-style: italic;"># dynamiquement (par exemple pour y ajouter une notion de temps qui passe).</span>
    <span style="color: #808080; font-style: italic;"># Donc, on propose de passer le template en paramètre  dans __init__ car la</span>
    <span style="color: #808080; font-style: italic;"># plupart du temps, c'est juste ce qu'on voudra faire : un simple changement</span>
    <span style="color: #808080; font-style: italic;"># cosmétique statique. Mais afin de permettre plus d'extensibilité, on en</span>
    <span style="color: #808080; font-style: italic;"># fait une propriété, qui, comme toute méthode, peut être écrasée avec de</span>
    <span style="color: #808080; font-style: italic;"># l'héritage et permettrait à l'utilisateur de vraiment personnaliser son</span>
    <span style="color: #808080; font-style: italic;"># affichage de manière poussée.</span>
    @<span style="color: #008000;">property</span>
    <span style="color: #ff7700;font-weight:bold;">def</span> template<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
        <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">self</span>._template
&nbsp;
    @template.<span style="color: black;">setter</span>
    <span style="color: #ff7700;font-weight:bold;">def</span> template<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, value<span style="color: black;">&#41;</span>:
        <span style="color: #008000;">self</span>._template = value
&nbsp;
    <span style="color: #808080; font-style: italic;"># C'est cette méthode qui est appelée si on a détourné sys.stdout quand</span>
    <span style="color: #808080; font-style: italic;"># l'utilisateur va faire un print. Elle doit s'appeler write(), car c'est</span>
    <span style="color: #808080; font-style: italic;"># l'interface connue des objets stream. Grosso modo, on va juste</span>
    <span style="color: #808080; font-style: italic;"># tout stocker dans une variable plutôt que d'afficher quoique ce soit</span>
    <span style="color: #ff7700;font-weight:bold;">def</span> write<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, value<span style="color: black;">&#41;</span>:
        <span style="color: #008000;">self</span>.<span style="color: black;">buffer</span> += value
&nbsp;
    <span style="color: #808080; font-style: italic;"># Pour une progrès donné, retourne la barre de progrès sous forme de</span>
    <span style="color: #808080; font-style: italic;"># string ASCII. Elle est mise à part car elle peut ainsi être facilement</span>
    <span style="color: #808080; font-style: italic;"># utilisée dans un callback.</span>
    <span style="color: #ff7700;font-weight:bold;">def</span> format<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, progress=<span style="color: #ff4500;">0</span><span style="color: black;">&#41;</span>:
        progress = progress <span style="color: #66cc66;">*</span> <span style="color: #ff4500;">100</span> / <span style="color: #008000;">self</span>.<span style="color: black;">total</span>
        bar = progress / <span style="color: #008000;">self</span>.<span style="color: black;">percent_per_sign</span> <span style="color: #66cc66;">*</span> <span style="color: #008000;">self</span>.<span style="color: black;">progress_sign</span>
        bar += <span style="color: black;">&#40;</span><span style="color: #008000;">self</span>.<span style="color: black;">bar_len</span> - <span style="color: #008000;">len</span><span style="color: black;">&#40;</span>bar<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span> <span style="color: #66cc66;">*</span> <span style="color: #483d8b;">' '</span>
        <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">self</span>.<span style="color: black;">template</span>.<span style="color: black;">format</span><span style="color: black;">&#40;</span>bar=bar, progress=progress<span style="color: black;">&#41;</span>
&nbsp;
&nbsp;
    <span style="color: #808080; font-style: italic;"># Notre callback que l'on utilise pour afficher la barre. C'est une méthode</span>
    <span style="color: #808080; font-style: italic;"># statique car cela nous permet de nous mettre dans les conditions exacte</span>
    <span style="color: #808080; font-style: italic;"># d'un callback d'un utilisateur, qui ne sera qu'une fonction, sans self.</span>
    @<span style="color: #008000;">staticmethod</span>
    <span style="color: #ff7700;font-weight:bold;">def</span> print_progress<span style="color: black;">&#40;</span>progress_bar, progress, previous_progress<span style="color: black;">&#41;</span>:
        <span style="color: #808080; font-style: italic;"># '\b' permet de reculer le curseur dans le terminal, ce qui va</span>
        <span style="color: #808080; font-style: italic;"># nous permettre de réécrire par dessus l'ancienne bar, et la mettre</span>
        <span style="color: #808080; font-style: italic;"># à jour. Si vous tenez à faire un display multi ligne, sachez que '\b'</span>
        <span style="color: #808080; font-style: italic;"># ne permet pas de reculer sur un saut de ligne, pour ça il faut</span>
        <span style="color: #808080; font-style: italic;"># utiliser '\033[1A'</span>
        progress_bar.<span style="color: black;">out</span>.<span style="color: black;">write</span><span style="color: black;">&#40;</span>progress_bar.<span style="color: black;">cursor_shift</span> <span style="color: #66cc66;">*</span> <span style="color: #483d8b;">'<span style="color: #000099; font-weight: bold;">\b</span>'</span><span style="color: black;">&#41;</span>
        bar = progress_bar.<span style="color: black;">format</span><span style="color: black;">&#40;</span>progress<span style="color: black;">&#41;</span>
        progress_bar.<span style="color: black;">out</span>.<span style="color: black;">write</span><span style="color: black;">&#40;</span>bar<span style="color: black;">&#41;</span>
        <span style="color: #808080; font-style: italic;"># flush est nécessaire pour vider le buffer et obtenir un affichage</span>
        <span style="color: #808080; font-style: italic;"># immédiat quand on écrit en direct sur un stream.</span>
        progress_bar.<span style="color: black;">out</span>.<span style="color: black;">flush</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
        <span style="color: #808080; font-style: italic;"># on met à jour l'avancement du curseur, qui nous permettra de reculer</span>
        <span style="color: #808080; font-style: italic;"># d'autant au prochain print_progress()</span>
        progress_bar.<span style="color: black;">cursor_shift</span> = <span style="color: #008000;">len</span><span style="color: black;">&#40;</span>bar<span style="color: black;">&#41;</span>
&nbsp;
&nbsp;
&nbsp;
<span style="color: #ff7700;font-weight:bold;">if</span> __name__ == <span style="color: #483d8b;">&quot;__main__&quot;</span>:
&nbsp;
    <span style="color: #808080; font-style: italic;"># voici une utilisation standard de la barre :</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">time</span>
&nbsp;
    total = <span style="color: #ff4500;">1000</span>
    <span style="color: #808080; font-style: italic;"># L'utilisation du context manager permet de ne pas se soucier d'appeler</span>
    <span style="color: #808080; font-style: italic;"># show() ou stop() et autre détails d'implémentation.</span>
    <span style="color: #808080; font-style: italic;"># On note aussi qu'avoir des valeurs par défaut pour l'initialisation de la</span>
    <span style="color: #808080; font-style: italic;"># barre la rend très facile à utiliser sans trop se prendre la tête, et</span>
    <span style="color: #808080; font-style: italic;"># ce malgré un code derrière assez complexe. On aurait même pu se passer</span>
    <span style="color: #808080; font-style: italic;"># de &quot;total&quot;.</span>
    <span style="color: #ff7700;font-weight:bold;">with</span> ProgressBar<span style="color: black;">&#40;</span>total<span style="color: black;">&#41;</span> <span style="color: #ff7700;font-weight:bold;">as</span> pb:
&nbsp;
        <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>total<span style="color: black;">&#41;</span>:
            <span style="color: #dc143c;">time</span>.<span style="color: black;">sleep</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">0.001</span><span style="color: black;">&#41;</span>
            <span style="color: #808080; font-style: italic;"># on voir l'interêt d'utiliser une property ici, ça rend la mise</span>
            <span style="color: #808080; font-style: italic;"># à jour du progrès très simple</span>
            pb.<span style="color: black;">progress</span> = i
            <span style="color: #ff7700;font-weight:bold;">if</span> i == total / <span style="color: #ff4500;">2</span>:
                <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;<span style="color: #000099; font-weight: bold;">\n</span>Half the work already !&quot;</span><span style="color: black;">&#41;</span>
                half = <span style="color: #008000;">True</span>
            <span style="color: #ff7700;font-weight:bold;">if</span> i == total <span style="color: #66cc66;">*</span> <span style="color: #ff4500;">0.7</span>:
                <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;Almost done&quot;</span><span style="color: black;">&#41;</span>
                almost = <span style="color: #008000;">True</span>
&nbsp;
        pb.<span style="color: black;">progress</span> = total
&nbsp;
    <span style="color: #808080; font-style: italic;"># On peut afficher tout ce qui a été printé durant la progression de la</span>
    <span style="color: #808080; font-style: italic;"># barre si besoin.</span>
    <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span>pb.<span style="color: black;">buffer</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">from</span> <span style="color: #dc143c;">datetime</span> <span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">datetime</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># Et une utilisation custo où on compte les secondes depuis le départ</span>
    <span style="color: #808080; font-style: italic;"># et on les affiches dans le template</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">class</span> MaProgressBar<span style="color: black;">&#40;</span>ProgressBar<span style="color: black;">&#41;</span>:
&nbsp;
        <span style="color: #ff7700;font-weight:bold;">def</span> show<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;">start</span> = <span style="color: #dc143c;">datetime</span>.<span style="color: black;">now</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
            <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">super</span><span style="color: black;">&#40;</span>MaProgressBar, <span style="color: #008000;">self</span><span style="color: black;">&#41;</span>.<span style="color: black;">show</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
        <span style="color: #808080; font-style: italic;"># Comme on a template en tant que méthode, on peut l'overrider et</span>
        <span style="color: #808080; font-style: italic;"># obtenir un comportement</span>
        @<span style="color: #008000;">property</span>
        <span style="color: #ff7700;font-weight:bold;">def</span> template<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
            seconds = <span style="color: black;">&#40;</span><span style="color: #dc143c;">datetime</span>.<span style="color: black;">now</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span> - <span style="color: #008000;">self</span>.<span style="color: black;">start</span><span style="color: black;">&#41;</span>.<span style="color: black;">seconds</span>
            <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #483d8b;">'{bar} (running for %s seconds)'</span> <span style="color: #66cc66;">%</span> seconds
&nbsp;
        @template.<span style="color: black;">setter</span>
        <span style="color: #ff7700;font-weight:bold;">def</span> template<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, value<span style="color: black;">&#41;</span>:
            <span style="color: #ff7700;font-weight:bold;">pass</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># Notre système de callback va se trouver utile :</span>
    <span style="color: #808080; font-style: italic;"># on met un callback de plus qui va écrire dans un fichier (mais</span>
    <span style="color: #808080; font-style: italic;"># il pourrait faire n'importe quoi, envoyer un post sur un site Web,</span>
    <span style="color: #808080; font-style: italic;"># un mail, formatter le disque...)</span>
    <span style="color: #ff7700;font-weight:bold;">def</span> update_progress<span style="color: black;">&#40;</span>progress_bar, progress, previous_progress<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><span style="color: #483d8b;">'/tmp/progress.log'</span>, <span style="color: #483d8b;">'w'</span><span style="color: black;">&#41;</span> <span style="color: #ff7700;font-weight:bold;">as</span> log:
            log.<span style="color: black;">write</span><span style="color: black;">&#40;</span><span style="color: #008000;">str</span><span style="color: black;">&#40;</span>progress<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># On change aussi le signe de progrès pour quelque chose de plus pro</span>
    pb = MaProgressBar<span style="color: black;">&#40;</span>progress_sign=<span style="color: #483d8b;">':-) '</span>, percent_per_sign=<span style="color: #ff4500;">10</span>,
                       callbacks=<span style="color: black;">&#40;</span>update_progress,<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># Au besoin, on peut passer à l'affichage en manuel.</span>
    pb.<span style="color: black;">show</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
    <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;">100</span><span style="color: black;">&#41;</span>:
        <span style="color: #dc143c;">time</span>.<span style="color: black;">sleep</span><span style="color: black;">&#40;</span>.1<span style="color: black;">&#41;</span>
        pb.<span style="color: black;">progress</span> = i
&nbsp;
    pb.<span style="color: black;">progress</span> = <span style="color: #ff4500;">100</span>
&nbsp;
    pb.<span style="color: black;">stop</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span></pre></div></div>

<hr />
<p><a href="https://github.com/sametmax/codes-des-articles/blob/master/2013/aout/progress_bar.py">Télécharger le code de l&#8217;article</a></p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=7122&amp;md5=4b21a908ab2fd1d97205099c6faa2b64" title="Flattr" target="_blank"><img src="media/fc229d00.flattr-badge-large.png" data-original-source="http://sametmax.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>


feed_id: http://sametmax.com/?p=7133
title: Django, une app à la fois : Outils pour templates
uri: Django-une-app-à-la-fois-Outils-pour-templates
url: http://sametmax.com/django-une-app-a-la-fois-outils-pour-templates/
content:
<p>Ouaaa, j&#8217;ai passé la journée sur ce truc. Il y avait beaucoup de texte pour une fois, alors la traduction anglais => français a pris pas mal de temps. C&#8217;est fou ce qu&#8217;on peut faire comme trucs chiants quand on a pas Internet&#8230;</p>
<p>Bref, je vous poste la nouvelle app de <a href="http://sametmax.com/django-une-app-a-la-fois/">Django, une app à la fois</a> depuis le Mac Do, parce que c&#8217;est le seul truc à avoir un Wifi dans le coin paumé où je me trouve.</p>
<p><a href="https://github.com/sametmax/Django--an-app-at-a-time/tree/fran%C3%A7ais">Machez bien, c&#8217;est assez dense.</a></p>
<p>P.S: ouinnnn, ils font plus le wrap chèvre.</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=7133&amp;md5=c052a00019c83f11c8bdc3c44809af6a" title="Flattr" target="_blank"><img src="media/fc229d00.flattr-badge-large.png" data-original-source="http://sametmax.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>


feed_id: http://sametmax.com/?p=647
title: Git push via HTTP (ou comment travailler au MacDo)
uri: Git-push-via-HTTP-(ou-comment-travailler-au-MacDo)
url: http://sametmax.com/git-push-via-http-ou-comment-travailler-au-macdo/
content:
<p>Hier, j’ai dû pusher du Mac Do. Parce que je suis dans un pli d&#8217;une circonvolution du sphincter du trou du cul du monde, à savoir chez mes grands-parents. Inutile de dire que j&#8217;avais un meilleur accès Internet à Kisumu, au Kenya. Si, si.</p>
<p>Bien entendu, le Mac wifi est annoncé comme &#8220;Internet gratuit Illimité&#8221;, ce qui en langage commercial ignorant signifie une partie du Web censurée et les ports de emails ouverts si vous nous achetez un maxi best of.</p>
<p>Donc pas de SSH.</p>
<p>Heurement Github est grand, Github est beau, et Github accepte les push via HTTPS.</p>
<p>Modifiez juste une ligne dans votre fichier .git/config de :</p>
<pre>
[remote "origin"]
	url = git@github.com/votre_pseudo/votre_repo.git</pre>
<p>Vers :</p>
<pre>
[remote "origin"]
	url = https://github.com/votre_pseudo/votre_repo.git</pre>
<p>La commande git devrait vous prompter pour username (mettez votre email) et mot de passe, et hop : le monde du télétravail à la campagne s&#8217;ouvre à vous.</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=647&amp;md5=5c22c578bb39a1bd2225d8742fa1a3af" title="Flattr" target="_blank"><img src="media/fc229d00.flattr-badge-large.png" data-original-source="http://sametmax.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>


feed_id: http://sametmax.com/?p=7143
title: S&#8217;affranchir des doublons d&#8217;un itérable en Python
uri: S-affranchir-des-doublons-d-un-itérable-en-Python
url: http://sametmax.com/saffranchir-des-doublons-dun-iterable-en-python/
content:
<p>Supprimer ou ignorer les doublons d&#8217;un itérable tel qu&#8217;une liste ou un array est un challenge dans tous les langages. Il faut se poser les questions suivantes :</p>
<ul>
<li>Qu&#8217;est-ce qu&#8217;un doublon ?</li>
<li>Quels types d&#8217;itérables traite-t-on ?</li>
<li>Quel est la taille de l&#8217;itérable ?</li>
<li>Et niveau perfs ?</li>
</ul>
<p>En Python, on a des structures de données qui suppriment automatiquement les doublons : les sets et les dictionnaires. Mais elles ne conservent pas l&#8217;ordre des élements.</p>
<p>Il y a aussi le fait qu&#8217;un itérable en Python peut avoir une taille inconnue, ou infinie.</p>
<p>Le post est long, donc&#8230;</p>

<!-- iframe plugin v:2.3 - wordpress.org/extend/plugins/iframe/ -->
<iframe width="420" height="315" src="//www.youtube.com/embed/HsX4M-by5OY" frameborder="0" scrolling="no" class="iframe-class"></iframe>
<h2>Solution 1 : générateur et hashing</h2>
<p>En utilisant conjointement les générateurs, les sets et une petite injection de dépendance, on peut trouver un compromis entre flexibilité et performances :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">def</span> skip_duplicates<span style="color: black;">&#40;</span>iterable, key=<span style="color: #ff7700;font-weight:bold;">lambda</span> x: x<span style="color: black;">&#41;</span>:
&nbsp;
    <span style="color: #808080; font-style: italic;"># on va mettre l’empreinte unique de chaque élément dans ce set</span>
    fingerprints = <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;">for</span> x <span style="color: #ff7700;font-weight:bold;">in</span> iterable:
        <span style="color: #808080; font-style: italic;"># chaque élement voit son emprunte calculée. Par défaut l’empreinte</span>
        <span style="color: #808080; font-style: italic;"># est l'élément lui même, ce qui fait qu'il n'y a pas besoin de</span>
        <span style="color: #808080; font-style: italic;"># spécifier 'key' pour des primitives comme les ints ou les strings.</span>
        fingerprint = key<span style="color: black;">&#40;</span>x<span style="color: black;">&#41;</span>
&nbsp;
        <span style="color: #808080; font-style: italic;"># On vérifie que l'empreinte est dans la liste des empreintes  des</span>
        <span style="color: #808080; font-style: italic;"># éléments précédents. Si ce n'est pas le cas, on yield l'élément, et on</span>
        <span style="color: #808080; font-style: italic;"># rajoute sont empreinte ans la liste de ceux trouvés, donc il ne sera</span>
        <span style="color: #808080; font-style: italic;"># pas yieldé si on ne le yieldera pas une seconde fois si on le</span>
        <span style="color: #808080; font-style: italic;"># rencontre à nouveau</span>
        <span style="color: #ff7700;font-weight:bold;">if</span> fingerprint <span style="color: #ff7700;font-weight:bold;">not</span> <span style="color: #ff7700;font-weight:bold;">in</span> fingerprints:
            <span style="color: #ff7700;font-weight:bold;">yield</span> x
            fingerprints.<span style="color: black;">add</span><span style="color: black;">&#40;</span>fingerprint<span style="color: black;">&#41;</span></pre></div></div>

<p>La fonction s&#8217;appelle <code>skip_duplicates</code> car c&#8217;est ce qu&#8217;elle fait. Elle ne retire pas vraiment les doublons, elle produit un flux de d&#8217;éléments qui ne comporte pas de doublons en ignorant tout doublons présent dans l&#8217;itérable initial.</p>
<p>Cette approche a plusieurs avantages :</p>
<ul>
<li>Les doublons sont bien retirés, et l&#8217;ordre est conservé.</li>
<li>La complexité est de 0(n).</li>
<li>L&#8217;utilisateur peut choisir ce qui fait qu&#8217;un élément est unique : un attribut, un sous-élément, l&#8217;affichage sous forme de string&#8230;</li>
<li>C&#8217;est un générateur, est cela fonctionne donc avec des itérables de toute taille, même inconnue ou infinie.</li>
</ul>
<p>Il faut néanmoins que l&#8217;ensemble des éléments uniques tiennent au moins une fois en mémoire en plus de l&#8217;itérable initial, et potentiellement d&#8217;un stockage à la sortie du générateur. On fait donc un trade-off sur la mémoire.</p>
<p>Comme la valeur de <code>key</code> par défaut est une valeur saine, ça fonctionne comme on s&#8217;y attend pour les cas simples :</p>

<div class="wp_syntax"><div 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>skip_duplicates<span style="color: black;">&#40;</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">1</span>, <span style="color: #ff4500;">2</span>, <span style="color: #ff4500;">3</span>, <span style="color: #ff4500;">4</span>, <span style="color: #ff4500;">4</span>, <span style="color: #ff4500;">2</span>, <span style="color: #ff4500;">1</span>, <span style="color: #ff4500;">3</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;">&#91;</span><span style="color: #ff4500;">1</span>, <span style="color: #ff4500;">2</span>, <span style="color: #ff4500;">3</span>, <span style="color: #ff4500;">4</span><span style="color: black;">&#93;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #008000;">list</span><span style="color: black;">&#40;</span>skip_duplicates<span style="color: black;">&#40;</span><span style="color: #483d8b;">'fjsqlkdmfjsklqmdfjdmsl'</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
<span style="color: black;">&#91;</span>u<span style="color: #483d8b;">'f'</span>, u<span style="color: #483d8b;">'j'</span>, u<span style="color: #483d8b;">'s'</span>, u<span style="color: #483d8b;">'q'</span>, u<span style="color: #483d8b;">'l'</span>, u<span style="color: #483d8b;">'k'</span>, u<span style="color: #483d8b;">'d'</span>, u<span style="color: #483d8b;">'m'</span><span style="color: black;">&#93;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #008000;">list</span><span style="color: black;">&#40;</span>skip_duplicates<span style="color: black;">&#40;</span><span style="color: black;">&#40;</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">1</span>, <span style="color: #ff4500;">2</span><span style="color: black;">&#41;</span>, <span style="color: black;">&#40;</span><span style="color: #ff4500;">2</span>, <span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span>, <span style="color: black;">&#40;</span><span style="color: #ff4500;">1</span>, <span style="color: #ff4500;">2</span><span style="color: black;">&#41;</span>, <span style="color: black;">&#40;</span><span style="color: #ff4500;">1</span>, <span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
<span style="color: black;">&#91;</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">1</span>, <span style="color: #ff4500;">2</span><span style="color: black;">&#41;</span>, <span style="color: black;">&#40;</span><span style="color: #ff4500;">2</span>, <span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span>, <span style="color: black;">&#40;</span><span style="color: #ff4500;">1</span>, <span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span><span style="color: black;">&#93;</span></pre></div></div>

<p>Pourvoir spécifier &#8216;key&#8217; permet de faire des choix dans ce qu&#8217;est un doublon :</p>

<div class="wp_syntax"><div 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>skip_duplicates<span style="color: black;">&#40;</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">1</span>, <span style="color: #ff4500;">2</span>, <span style="color: #483d8b;">'1'</span>, <span style="color: #483d8b;">'1'</span>, <span style="color: #ff4500;">2</span>, <span style="color: #ff4500;">3</span>, <span style="color: #483d8b;">'3'</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
<span style="color: black;">&#91;</span><span style="color: #ff4500;">1</span>, <span style="color: #ff4500;">2</span>, u<span style="color: #483d8b;">'1'</span>, <span style="color: #ff4500;">3</span>, u<span style="color: #483d8b;">'3'</span><span style="color: black;">&#93;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #008000;">list</span><span style="color: black;">&#40;</span>skip_duplicates<span style="color: black;">&#40;</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">1</span>, <span style="color: #ff4500;">2</span>, <span style="color: #483d8b;">'1'</span>, <span style="color: #483d8b;">'1'</span>, <span style="color: #ff4500;">2</span>, <span style="color: #ff4500;">3</span>, <span style="color: #483d8b;">'3'</span><span style="color: black;">&#41;</span>, key=<span style="color: #ff7700;font-weight:bold;">lambda</span> x: <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><span style="color: black;">&#41;</span>
<span style="color: black;">&#91;</span><span style="color: #ff4500;">1</span>, <span style="color: #ff4500;">2</span>, <span style="color: #ff4500;">3</span><span style="color: black;">&#93;</span></pre></div></div>

<p>Et si on s&#8217;attaque à des cas plus complexes, le fonction vous force à préciser votre pensée :</p>

<div class="wp_syntax"><div 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>skip_duplicates<span style="color: black;">&#40;</span><span style="color: black;">&#40;</span><span style="color: black;">&#91;</span><span style="color: black;">&#93;</span>, <span style="color: black;">&#91;</span><span style="color: black;">&#93;</span>, <span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>, <span style="color: black;">&#91;</span><span style="color: #ff4500;">1</span>, <span style="color: #ff4500;">2</span><span style="color: black;">&#93;</span>, <span style="color: black;">&#40;</span><span style="color: #ff4500;">1</span>, <span style="color: #ff4500;">2</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
... <span style="color: black;">&#41;</span>
Traceback <span style="color: black;">&#40;</span>most recent call last<span style="color: black;">&#41;</span>:
  File <span style="color: #483d8b;">&quot;&lt;ipython-input-20-ed44f170c634&gt;&quot;</span>, line <span style="color: #ff4500;">1</span>, <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #66cc66;">&lt;</span>module<span style="color: #66cc66;">&gt;</span>
    <span style="color: #008000;">list</span><span style="color: black;">&#40;</span>skip_duplicates<span style="color: black;">&#40;</span><span style="color: black;">&#40;</span><span style="color: black;">&#91;</span><span style="color: black;">&#93;</span>, <span style="color: black;">&#91;</span><span style="color: black;">&#93;</span>, <span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>, <span style="color: black;">&#91;</span><span style="color: #ff4500;">1</span>, <span style="color: #ff4500;">2</span><span style="color: black;">&#93;</span>, <span style="color: black;">&#40;</span><span style="color: #ff4500;">1</span>, <span style="color: #ff4500;">2</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
  File <span style="color: #483d8b;">&quot;&lt;ipython-input-18-42dbb94f03f8&gt;&quot;</span>, line <span style="color: #ff4500;">7</span>, <span style="color: #ff7700;font-weight:bold;">in</span> skip_duplicates
    <span style="color: #ff7700;font-weight:bold;">if</span> fingerprint <span style="color: #ff7700;font-weight:bold;">not</span> <span style="color: #ff7700;font-weight:bold;">in</span> fingerprints:
<span style="color: #008000;">TypeError</span>: unhashable <span style="color: #008000;">type</span>: <span style="color: #483d8b;">'list'</span></pre></div></div>

<p>En effet les listes ne sont pas des types hashables en Python, on ne peut donc pas les stocker dans un <code>set</code>.</p>
<p>Mais on peut caster la liste, et faire ainsi le choix de savoir sur quel critère on base notre égalité. Par exemle, considère-t-on que deux itérables ayant le même contenu sont égaux, où alors doivent-ils avoir le même type ?</p>

<div class="wp_syntax"><div 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>skip_duplicates<span style="color: black;">&#40;</span><span style="color: black;">&#40;</span><span style="color: black;">&#91;</span><span style="color: black;">&#93;</span>, <span style="color: black;">&#91;</span><span style="color: black;">&#93;</span>, <span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>, <span style="color: black;">&#91;</span><span style="color: #ff4500;">1</span>, <span style="color: #ff4500;">2</span><span style="color: black;">&#93;</span>, <span style="color: black;">&#40;</span><span style="color: #ff4500;">1</span>, <span style="color: #ff4500;">2</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>, <span style="color: #ff7700;font-weight:bold;">lambda</span> x: <span style="color: #008000;">tuple</span><span style="color: black;">&#40;</span>x<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
<span style="color: black;">&#91;</span><span style="color: black;">&#91;</span><span style="color: black;">&#93;</span>, <span style="color: black;">&#91;</span><span style="color: #ff4500;">1</span>, <span style="color: #ff4500;">2</span><span style="color: black;">&#93;</span><span style="color: black;">&#93;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #008000;">list</span><span style="color: black;">&#40;</span>skip_duplicates<span style="color: black;">&#40;</span><span style="color: black;">&#40;</span><span style="color: black;">&#91;</span><span style="color: black;">&#93;</span>, <span style="color: black;">&#91;</span><span style="color: black;">&#93;</span>, <span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>, <span style="color: black;">&#91;</span><span style="color: #ff4500;">1</span>, <span style="color: #ff4500;">2</span><span style="color: black;">&#93;</span>, <span style="color: black;">&#40;</span><span style="color: #ff4500;">1</span>, <span style="color: #ff4500;">2</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>, <span style="color: #ff7700;font-weight:bold;">lambda</span> x: <span style="color: black;">&#40;</span><span style="color: #008000;">type</span><span style="color: black;">&#40;</span>x<span style="color: black;">&#41;</span>, <span style="color: #008000;">tuple</span><span style="color: black;">&#40;</span>x<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
<span style="color: black;">&#91;</span><span style="color: black;">&#91;</span><span style="color: black;">&#93;</span>, <span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>, <span style="color: black;">&#91;</span><span style="color: #ff4500;">1</span>, <span style="color: #ff4500;">2</span><span style="color: black;">&#93;</span>, <span style="color: black;">&#40;</span><span style="color: #ff4500;">1</span>, <span style="color: #ff4500;">2</span><span style="color: black;">&#41;</span><span style="color: black;">&#93;</span></pre></div></div>

<p>Nous utilisons le fait que :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #008000;">tuple</span><span style="color: black;">&#40;</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">1</span>, <span style="color: #ff4500;">2</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span> == <span style="color: black;">&#40;</span><span style="color: #ff4500;">1</span>, <span style="color: #ff4500;">2</span><span style="color: black;">&#41;</span>
<span style="color: #008000;">True</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: black;">&#40;</span><span style="color: #008000;">type</span><span style="color: black;">&#40;</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">1</span>, <span style="color: #ff4500;">2</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span>, <span style="color: #008000;">tuple</span><span style="color: black;">&#40;</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">1</span>, <span style="color: #ff4500;">2</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span> == <span style="color: black;">&#40;</span><span style="color: #008000;">type</span><span style="color: black;">&#40;</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">1</span>, <span style="color: #ff4500;">2</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>, <span style="color: black;">&#40;</span><span style="color: #ff4500;">1</span>, <span style="color: #ff4500;">2</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
<span style="color: #008000;">False</span></pre></div></div>

<p>Puisque :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: black;">&#40;</span><span style="color: #008000;">type</span><span style="color: black;">&#40;</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">1</span>, <span style="color: #ff4500;">2</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span>, <span style="color: #008000;">tuple</span><span style="color: black;">&#40;</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">1</span>, <span style="color: #ff4500;">2</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
<span style="color: black;">&#40;</span><span style="color: #66cc66;">&lt;</span>type <span style="color: #483d8b;">'list'</span><span style="color: #66cc66;">&gt;</span>, <span style="color: black;">&#40;</span><span style="color: #ff4500;">1</span>, <span style="color: #ff4500;">2</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: black;">&#40;</span><span style="color: #008000;">type</span><span style="color: black;">&#40;</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">1</span>, <span style="color: #ff4500;">2</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>, <span style="color: black;">&#40;</span><span style="color: #ff4500;">1</span>, <span style="color: #ff4500;">2</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
<span style="color: black;">&#40;</span><span style="color: #66cc66;">&lt;</span>type <span style="color: #483d8b;">'tuple'</span><span style="color: #66cc66;">&gt;</span>, <span style="color: black;">&#40;</span><span style="color: #ff4500;">1</span>, <span style="color: #ff4500;">2</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span></pre></div></div>

<p>Dans le cas où nous ne sommes pas capables de déterminer ce qu&#8217;est un doublon, la fonction ne retire simplement rien :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">class</span> Test<span style="color: black;">&#40;</span><span style="color: #008000;">object</span><span style="color: black;">&#41;</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>, foo=<span style="color: #483d8b;">'bar'</span><span style="color: black;">&#41;</span>:
        <span style="color: #008000;">self</span>.<span style="color: black;">foo</span> = foo
    <span style="color: #ff7700;font-weight:bold;">def</span> <span style="color: #0000cd;">__repr__</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
        <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #483d8b;">&quot;Test('%s')&quot;</span> <span style="color: #66cc66;">%</span> <span style="color: #008000;">self</span>.<span style="color: black;">foo</span>
&nbsp;
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #008000;">list</span><span style="color: black;">&#40;</span>skip_duplicates<span style="color: black;">&#40;</span><span style="color: black;">&#91;</span>Test<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>, Test<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>, Test<span style="color: black;">&#40;</span><span style="color: #483d8b;">'other'</span><span style="color: black;">&#41;</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>Test<span style="color: black;">&#40;</span><span style="color: #483d8b;">'bar'</span><span style="color: black;">&#41;</span>, Test<span style="color: black;">&#40;</span><span style="color: #483d8b;">'bar'</span><span style="color: black;">&#41;</span>, Test<span style="color: black;">&#40;</span><span style="color: #483d8b;">'other'</span><span style="color: black;">&#41;</span><span style="color: black;">&#93;</span></pre></div></div>

<p>Mais permet encore une fois de faire le choix de quoi retirer :</p>

<div class="wp_syntax"><div 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>skip_duplicates<span style="color: black;">&#40;</span><span style="color: black;">&#91;</span>Test<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>, Test<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>, Test<span style="color: black;">&#40;</span><span style="color: #483d8b;">'other'</span><span style="color: black;">&#41;</span><span style="color: black;">&#93;</span>, key=<span style="color: #ff7700;font-weight:bold;">lambda</span> x: x.<span style="color: black;">foo</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
<span style="color: black;">&#91;</span>Test<span style="color: black;">&#40;</span><span style="color: #483d8b;">'bar'</span><span style="color: black;">&#41;</span>, Test<span style="color: black;">&#40;</span><span style="color: #483d8b;">'other'</span><span style="color: black;">&#41;</span><span style="color: black;">&#93;</span></pre></div></div>

<p>Ce principe de la fonction <code>key</code>, on le retrouve dans <code>sorted()</code>, donc les habitués seront déjà à l&#8217;aise. Et j&#8217;aime beaucoup ce pattern, car il est très puissant. On peut avoir la fonction <code>key</code> qui renvoit des choses très simples :</p>
<ul>
<li>Un attribut.</li>
<li>Un element (<code>x[2]</code>, <code>x['cle']</code>&#8230;)</li>
<li>Une version castée avec <code>int()</code>, <code>str()</code>, <code>tuple()</code>, etc</li>
</ul>
<p>Mais on peut aussi faire des choses très complexes. En effet, rien ne nous oblige à utiliser une lambda, on peut mettre une fonction complète et lui faire retourner :</p>
<ul>
<li>Un hash md5.</li>
<li>Une entrée en base de données.</li>
<li>Un nouvel objet customisé.</li>
<li>Un tuple de tuples d&#8217;objets custos avec des dictionnaires en attributs&#8230;</li>
<li>Le contenu d&#8217;un fichier.</li>
</ul>
<p>Python sait naturellement comparer tout ça.</p>
<p>Notez que nous trichons un peu, puisque nous retirons les doublons en nous basant sur un <code>set</code> qui va calculer un hash de l&#8217;objet, et pas véritablement vérifier l&#8217;égalité. La fonction en fonctionnera donc pas si l&#8217;utilisateur définie <code>__eq__</code> et s&#8217;attend à ce que les doublons soient retirés. Ce qui nous amène à &#8230;</p>
<h2>Solution 2 : iterateur et comparaison</h2>
<p>Pour ce genre de chose, un autre algo, qui ne fontionerait que sur les itérables de taille finie, et qui serait bien plus lent (complexité n log(n)), peut être utilisé :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">def</span> strip_duplicates<span style="color: black;">&#40;</span>iterable, equals=<span style="color: #ff7700;font-weight:bold;">lambda</span> x, y: x == y<span style="color: black;">&#41;</span>:
&nbsp;
    <span style="color: #808080; font-style: italic;"># On transforme l'itérable en iterateur sur lui même, cela va nous</span>
    <span style="color: #808080; font-style: italic;"># permettre d'appeler next() dessus et récupérer le premier élément,</span>
    <span style="color: #808080; font-style: italic;"># même sur un objet non indexable (sur lequel on ne peut utiliser [0])</span>
    iterable = <span style="color: #008000;">iter</span><span style="color: black;">&#40;</span>iterable<span style="color: black;">&#41;</span>
&nbsp;
    res = <span style="color: black;">&#91;</span><span style="color: black;">&#93;</span>
    <span style="color: #808080; font-style: italic;"># Une petite boucle infinie est nécessaire car la boucle 'for' ne nous</span>
    <span style="color: #808080; font-style: italic;"># permet pas de récupérer le premier élément indépendamment des autres,</span>
    <span style="color: #808080; font-style: italic;"># et la boucle 'while' attend une condition de sortie, ce que nous n'avons</span>
    <span style="color: #808080; font-style: italic;"># pas forcément (il n'est pas possible de vérifier le nombre d'éléments</span>
    <span style="color: #808080; font-style: italic;"># restant dans un générateur).</span>
    <span style="color: #ff7700;font-weight:bold;">while</span> <span style="color: #008000;">True</span>:
&nbsp;
        <span style="color: #808080; font-style: italic;"># on récupère le premier élément de l'iterable restant, si il n'y en</span>
        <span style="color: #808080; font-style: italic;"># a plus, on sort de la boucle.</span>
        <span style="color: #ff7700;font-weight:bold;">try</span>:
            elem = next<span style="color: black;">&#40;</span>iterable<span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">except</span> <span style="color: #008000;">StopIteration</span>:
            <span style="color: #ff7700;font-weight:bold;">break</span>
&nbsp;
        <span style="color: #808080; font-style: italic;"># Le premier élément est ajouté au résultat sans doublons. Maintenant</span>
        <span style="color: #808080; font-style: italic;"># on va recréer l'itérable, mais en retirant tout ce qui était égal</span>
        <span style="color: #808080; font-style: italic;"># au premier élément. Notez que 'être égal' est une condition modifiable</span>
        <span style="color: #808080; font-style: italic;"># en passant une fonction en paramètre, comme l'était 'key' précédemment.</span>
        res.<span style="color: black;">append</span><span style="color: black;">&#40;</span>elem<span style="color: black;">&#41;</span>
&nbsp;
        iterable = <span style="color: #008000;">iter</span><span style="color: black;">&#40;</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> iterable <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #ff7700;font-weight:bold;">not</span> equals<span style="color: black;">&#40;</span>elem, x<span style="color: black;">&#41;</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">return</span> res</pre></div></div>

<p>La fonction s&#8217;appelle <code>strip_duplicates</code> car elle produit une nouvelle liste, mais sans les éléments indésirables, comme le fait <code>strip()</code> sur une chaîne (produit une nouvelle chaîne, sans les éléments indésirables).</p>
<p>Ce type de fonction peut être utile dans plusieurs cas :</p>
<ul>
<li>On a pas envie de se poser la question de savoir si nos types à comparer sont hashable ou pas, et on est prêt à payer un peu de CPU pour cela.</li>
<li>On a besoin de retirer les doublons sur la base d&#8217;une égalité, par exemple sur l&#8217;existence de la méthode <code>__eq__</code>.</li>
<li>On a besoin de retirer les doublons sur la base d&#8217;une logique complexe qui dépend du contexte.</li>
</ul>
<p>A première vu cela fonctionne presque de la même manière que <code>skip_duplicates</code>, mais en retournant une liste plutôt qu&#8217;un générateur :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">&gt;&gt;&gt;</span> strip_duplicates<span style="color: black;">&#40;</span><span style="color: #483d8b;">'fdjqkslfjdmkfdsqjkfmjqsdmlkfjqslkmfjsdklfl'</span><span style="color: black;">&#41;</span>
<span style="color: black;">&#91;</span><span style="color: #483d8b;">'f'</span>, <span style="color: #483d8b;">'d'</span>, <span style="color: #483d8b;">'j'</span>, <span style="color: #483d8b;">'q'</span>, <span style="color: #483d8b;">'k'</span>, <span style="color: #483d8b;">'s'</span>, <span style="color: #483d8b;">'l'</span>, <span style="color: #483d8b;">'m'</span><span style="color: black;">&#93;</span></pre></div></div>

<p>Mais déjà il n&#8217;y a pas à se soucier de savoir si une structure de données est hashable :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">&gt;&gt;&gt;</span> strip_duplicates<span style="color: black;">&#40;</span><span style="color: black;">&#40;</span><span style="color: black;">&#91;</span><span style="color: black;">&#93;</span>, <span style="color: black;">&#91;</span><span style="color: black;">&#93;</span>, <span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>, <span style="color: black;">&#91;</span><span style="color: #ff4500;">1</span>, <span style="color: #ff4500;">2</span><span style="color: black;">&#93;</span>, <span style="color: black;">&#40;</span><span style="color: #ff4500;">1</span>, <span style="color: #ff4500;">2</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
<span style="color: black;">&#91;</span><span style="color: black;">&#91;</span><span style="color: black;">&#93;</span>, <span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>, <span style="color: black;">&#91;</span><span style="color: #ff4500;">1</span>, <span style="color: #ff4500;">2</span><span style="color: black;">&#93;</span>, <span style="color: black;">&#40;</span><span style="color: #ff4500;">1</span>, <span style="color: #ff4500;">2</span><span style="color: black;">&#41;</span><span style="color: black;">&#93;</span></pre></div></div>

<p>Même si on garde la même flexibilité, bien que la fonction à passer ait une signature légèrement différente :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">&gt;&gt;&gt;</span> strip_duplicates<span style="color: black;">&#40;</span><span style="color: black;">&#40;</span><span style="color: black;">&#91;</span><span style="color: black;">&#93;</span>, <span style="color: black;">&#91;</span><span style="color: black;">&#93;</span>, <span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>, <span style="color: black;">&#91;</span><span style="color: #ff4500;">1</span>, <span style="color: #ff4500;">2</span><span style="color: black;">&#93;</span>, <span style="color: black;">&#40;</span><span style="color: #ff4500;">1</span>, <span style="color: #ff4500;">2</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>, <span style="color: #ff7700;font-weight:bold;">lambda</span> x, y: <span style="color: #008000;">tuple</span><span style="color: black;">&#40;</span>x<span style="color: black;">&#41;</span> == <span style="color: #008000;">tuple</span><span style="color: black;">&#40;</span>y<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
<span style="color: black;">&#91;</span><span style="color: black;">&#91;</span><span style="color: black;">&#93;</span>, <span style="color: black;">&#91;</span><span style="color: #ff4500;">1</span>, <span style="color: #ff4500;">2</span><span style="color: black;">&#93;</span><span style="color: black;">&#93;</span></pre></div></div>

<p>Le plus interessant reste que cela fonctionne sur l&#8217;égalité, et donc cela marche d&#8217;office avec les objets qui déclarent <code>__eq__</code> ce qui est le cas dans de nombreuses libs, comme les ORM :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">class</span> Test<span style="color: black;">&#40;</span><span style="color: #008000;">object</span><span style="color: black;">&#41;</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>, foo=<span style="color: #483d8b;">'bar'</span><span style="color: black;">&#41;</span>:
        <span style="color: #008000;">self</span>.<span style="color: black;">foo</span> = foo
    <span style="color: #ff7700;font-weight:bold;">def</span> <span style="color: #0000cd;">__repr__</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
        <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #483d8b;">&quot;Test('%s')&quot;</span> <span style="color: #66cc66;">%</span> <span style="color: #008000;">self</span>.<span style="color: black;">foo</span>
    <span style="color: #ff7700;font-weight:bold;">def</span> <span style="color: #0000cd;">__eq__</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, other<span style="color: black;">&#41;</span>:
        <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">self</span>.<span style="color: black;">foo</span> == other.<span style="color: black;">foo</span>
&nbsp;
<span style="color: #66cc66;">&gt;&gt;&gt;</span> strip_duplicates<span style="color: black;">&#40;</span><span style="color: black;">&#91;</span>Test<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>, Test<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>, Test<span style="color: black;">&#40;</span><span style="color: #483d8b;">'other'</span><span style="color: black;">&#41;</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span>
<span style="color: black;">&#91;</span>Test<span style="color: black;">&#40;</span><span style="color: #483d8b;">'bar'</span><span style="color: black;">&#41;</span>, Test<span style="color: black;">&#40;</span><span style="color: #483d8b;">'other'</span><span style="color: black;">&#41;</span><span style="color: black;">&#93;</span></pre></div></div>

<p>Dans certains cas, notamment dans le cas où le point de comparaison est un object non hashable de très grosse taille (par exemple un dico très long), on peut espérer aussi pas mal économiser en mémoire. Mais on est qu&#8217;en est-il des besoins en mémoire et en CPU ?</p>
<h2>Solution 3 : retirer les doublons, in place</h2>
<p>Enfin, pour ceux qui ont de grosses contraintes de mémoire et qui veulent un algo rapide au prix de la flexibilité du code, voici une solution qui oblige à travailler sur des listes et à modifier la liste sur place :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">def</span> remove_duplicates<span style="color: black;">&#40;</span>lst, equals=<span style="color: #ff7700;font-weight:bold;">lambda</span> x, y: x == y<span style="color: black;">&#41;</span>:
&nbsp;
    <span style="color: #808080; font-style: italic;"># Normalement en Python on adore le duck typing, mais là cet algo suppose</span>
    <span style="color: #808080; font-style: italic;"># l'usage d'une liste, donc on met un gardefou.</span>
    <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #ff7700;font-weight:bold;">not</span> <span style="color: #008000;">isinstance</span><span style="color: black;">&#40;</span>lst, <span style="color: #008000;">list</span><span style="color: black;">&#41;</span>:
        <span style="color: #ff7700;font-weight:bold;">raise</span> <span style="color: #008000;">TypeError</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'This function works only with lists.'</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># là on est sur quelque chose qui ressemble vachement plus à du code C ^^</span>
    i1 = <span style="color: #ff4500;">0</span>
    l = <span style="color: black;">&#40;</span><span style="color: #008000;">len</span><span style="color: black;">&#40;</span>lst<span style="color: black;">&#41;</span> - <span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># on itère mécaniquement sur la liste, à l'ancienne, avec nos petites</span>
    <span style="color: #808080; font-style: italic;"># mains potelées.</span>
    <span style="color: #ff7700;font-weight:bold;">while</span> i1 <span style="color: #66cc66;">&lt;</span> l:
&nbsp;
        <span style="color: #808080; font-style: italic;"># on récupère chaque élément de la liste, sauf le dernier</span>
        elem = lst<span style="color: black;">&#91;</span>i1<span style="color: black;">&#93;</span>
&nbsp;
        <span style="color: #808080; font-style: italic;"># on le compare à l'élément suivant, et chaque élément après</span>
        <span style="color: #808080; font-style: italic;"># l'élément suivant</span>
        i2 = i1 + <span style="color: #ff4500;">1</span>
        <span style="color: #ff7700;font-weight:bold;">while</span> i2 <span style="color: #66cc66;">&lt;</span>= l:
            <span style="color: #808080; font-style: italic;"># en cas d'égalité, on retire l'élément de la liste, et on</span>
            <span style="color: #808080; font-style: italic;"># décrément la longueur de la liste ainsi amputée</span>
            <span style="color: #ff7700;font-weight:bold;">if</span> equals<span style="color: black;">&#40;</span>elem, lst<span style="color: black;">&#91;</span>i2<span style="color: black;">&#93;</span><span style="color: black;">&#41;</span>:
                <span style="color: #ff7700;font-weight:bold;">del</span> lst<span style="color: black;">&#91;</span>i2<span style="color: black;">&#93;</span>
                l -= <span style="color: #ff4500;">1</span>
            i2 += <span style="color: #ff4500;">1</span>
&nbsp;
        i1 += <span style="color: #ff4500;">1</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">return</span> lst</pre></div></div>

<p>Et là on est bien dans de la modification sur place :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">&gt;&gt;&gt;</span> lst = <span style="color: #008000;">list</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'fjdsklmqfjskdfjmld'</span><span style="color: black;">&#41;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> lst
<span style="color: black;">&#91;</span>u<span style="color: #483d8b;">'f'</span>, u<span style="color: #483d8b;">'j'</span>, u<span style="color: #483d8b;">'d'</span>, u<span style="color: #483d8b;">'s'</span>, u<span style="color: #483d8b;">'k'</span>, u<span style="color: #483d8b;">'l'</span>, u<span style="color: #483d8b;">'m'</span>, u<span style="color: #483d8b;">'q'</span>, u<span style="color: #483d8b;">'f'</span>, u<span style="color: #483d8b;">'j'</span>, u<span style="color: #483d8b;">'s'</span>, u<span style="color: #483d8b;">'k'</span>, u<span style="color: #483d8b;">'d'</span>, u<span style="color: #483d8b;">'f'</span>, u<span style="color: #483d8b;">'j'</span>, u<span style="color: #483d8b;">'m'</span>, u<span style="color: #483d8b;">'l'</span>, u<span style="color: #483d8b;">'d'</span><span style="color: black;">&#93;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> remove_duplicates<span style="color: black;">&#40;</span>lst<span style="color: black;">&#41;</span>
<span style="color: black;">&#91;</span>u<span style="color: #483d8b;">'f'</span>, u<span style="color: #483d8b;">'j'</span>, u<span style="color: #483d8b;">'d'</span>, u<span style="color: #483d8b;">'s'</span>, u<span style="color: #483d8b;">'k'</span>, u<span style="color: #483d8b;">'l'</span>, u<span style="color: #483d8b;">'m'</span>, u<span style="color: #483d8b;">'q'</span><span style="color: black;">&#93;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> lst
<span style="color: black;">&#91;</span>u<span style="color: #483d8b;">'f'</span>, u<span style="color: #483d8b;">'j'</span>, u<span style="color: #483d8b;">'d'</span>, u<span style="color: #483d8b;">'s'</span>, u<span style="color: #483d8b;">'k'</span>, u<span style="color: #483d8b;">'l'</span>, u<span style="color: #483d8b;">'m'</span>, u<span style="color: #483d8b;">'q'</span><span style="color: black;">&#93;</span></pre></div></div>

<p>La fonction s&#8217;appelle cette fois bien <code>remove_duplicates</code> puisque c&#8217;est ce qu&#8217;elle fait : retirer les doublons de la liste originale.</p>
<h2>Et maintenant, c&#8217;est l&#8217;heure du benchmark à deux balles !</h2>
<p>skip_duplicates :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">setup = <span style="color: #483d8b;">&quot;&quot;&quot;
def skip_duplicates(iterable, key=lambda x: x):
        fingerprints = set()
        for x in iterable:
                fingerprint = key(x)
                if fingerprint not in fingerprints:
                        yield x
                        fingerprints.add(fingerprint)
import string
lst = list(string.ascii_letters * 100)&quot;&quot;&quot;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #dc143c;">timeit</span>.<span style="color: #dc143c;">timeit</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'list(skip_duplicates(lst))'</span>, setup=setup, number=<span style="color: #ff4500;">1000</span><span style="color: black;">&#41;</span>
<span style="color: #ff4500;">0.9810519218444824</span></pre></div></div>

<p>strip_duplicates :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">&gt;&gt;&gt;</span> setup = <span style="color: #483d8b;">&quot;&quot;&quot;
def strip_duplicates(iterable, equals=lambda x, y: x == y):
    iterable = iter(iterable)
    res = []
    while True:
        try:
            elem = next(iterable)
        except StopIteration:
            break
        res.append(elem)
&nbsp;
        iterable = iter([x for x in iterable if not equals(elem, x)])
&nbsp;
    return res
&nbsp;
import string
lst = list(string.ascii_letters * 100)&quot;&quot;&quot;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #dc143c;">timeit</span>.<span style="color: #dc143c;">timeit</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'list(strip_duplicates(lst))'</span>, setup=setup, number=<span style="color: #ff4500;">1000</span><span style="color: black;">&#41;</span>
<span style="color: #ff4500;">41.462974071502686</span></pre></div></div>

<p>remove_duplicates :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">setup = <span style="color: #483d8b;">&quot;&quot;&quot;
def remove_duplicates(lst, equals=lambda x, y: x == y):
    if not isinstance(lst, list):
        raise TypeError('This function works only with lists.')
    i1 = 0
    l = (len(lst) - 1)
    while i1 &lt; l:
        elem = lst[i1]
        i2 = i1 + 1
        while i2 &lt;= l:
            if equals(elem, lst[i2]):
                del lst[i2]
                l -= 1
            i2 += 1
        i1 += 1
    return lst
&nbsp;
import string
lst = list(string.ascii_letters * 100)&quot;&quot;&quot;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #dc143c;">timeit</span>.<span style="color: #dc143c;">timeit</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'list(remove_duplicates(lst))'</span>, setup=setup, number=<span style="color: #ff4500;">1000</span><span style="color: black;">&#41;</span>
<span style="color: #ff4500;">0.37493896484375</span></pre></div></div>

<p>Sans surprise, la version inplace est la plus rapide puisque la plus restrictive. En second vient notre strip_duplicates, beaucoup fois plus lente. Et en dernier, 50 fois plus lente, le compromis entre les deux : souple, consomme moins de mémoire que skip, mais plus que remove.</p>
<p>Mais ce n&#8217;est pas très juste pour strip, puisque que skip n&#8217;a pas à faire un gros travail de conversion. Essayons avec des clés plus grosses :</p>
<p>skip_duplicates :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">setup = <span style="color: #483d8b;">&quot;&quot;&quot;
def skip_duplicates(iterable, key=lambda x: x):
        fingerprints = set()
        for x in iterable:
                fingerprint = key(x)
                if fingerprint not in fingerprints:
                        yield x
                        fingerprints.add(fingerprint)
import string, random
lst = [list(string.ascii_letters * 100) for x in xrange(100)]
for x in lst:
    x.pop(random.randint(0, len(x) - 1))&quot;&quot;&quot;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #dc143c;">timeit</span>.<span style="color: #dc143c;">timeit</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'list(skip_duplicates(lst, lambda x: tuple(x)))'</span>, setup=setup, number=<span style="color: #ff4500;">1000</span><span style="color: black;">&#41;</span>
<span style="color: #ff4500;">15.516181945800781</span></pre></div></div>

<p>strip_duplicates :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">&gt;&gt;&gt;</span> setup = <span style="color: #483d8b;">&quot;&quot;&quot;
def strip_duplicates(iterable, equals=lambda x, y: x == y):
    iterable = iter(iterable)
    res = []
    while True:
        try:
            elem = next(iterable)
        except StopIteration:
            break
        res.append(elem)
&nbsp;
        iterable = iter([x for x in iterable if not equals(elem, x)])
&nbsp;
    return res
&nbsp;
import string, random
lst = [list(string.ascii_letters * 100) for x in xrange(100)]
for x in lst:
    x.pop(random.randint(0, len(x) - 1))&quot;&quot;&quot;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #dc143c;">timeit</span>.<span style="color: #dc143c;">timeit</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'list(strip_duplicates(lst))'</span>, setup=setup, number=<span style="color: #ff4500;">1000</span><span style="color: black;">&#41;</span>
<span style="color: #ff4500;">22.047110080718994</span></pre></div></div>

<p>remove_duplicates :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">setup = <span style="color: #483d8b;">&quot;&quot;&quot;
def remove_duplicates(lst, equals=lambda x, y: x == y):
    if not isinstance(lst, list):
        raise TypeError('This function works only with lists.')
    i1 = 0
    l = (len(lst) - 1)
    while i1 &lt; l:
        elem = lst[i1]
        i2 = i1 + 1
        while i2 &lt;= l:
            if equals(elem, lst[i2]):
                del lst[i2]
                l -= 1
            i2 += 1
        i1 += 1
    return lst
&nbsp;
import string, random
lst = [list(string.ascii_letters * 100) for x in xrange(100)]
for x in lst:
    x.pop(random.randint(0, len(x) - 1))&quot;&quot;&quot;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #dc143c;">timeit</span>.<span style="color: #dc143c;">timeit</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'list(remove_duplicates(lst))'</span>, setup=setup, number=<span style="color: #ff4500;">1000</span><span style="color: black;">&#41;</span>
<span style="color: #ff4500;">14.763166904449463</span></pre></div></div>

<p>Comme souvent les résultats sont contre untuitifs, car bien que remove garde son avance, elle s&#8217;est largement réduite. A l&#8217;inverse, skip n&#8217;est pas tant à la ramasse que ça, et strip reste le plus lent.</p>
<p>Il faudrait aussi mesurer la consommation mémoire, je suis certain que ce serait interessant.</p>
<p>Bon, il est temps de mettre tout ça dans <a href="http://sametmax.com/batbelt-la-lib-des-petits-outils-python-qui-vont-bien/">batbelt</a>.</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=7143&amp;md5=3d2ef2768ecef0765e05660abbbcf20f" title="Flattr" target="_blank"><img src="media/fc229d00.flattr-badge-large.png" data-original-source="http://sametmax.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>


feed_id: http://sametmax.com/?p=7150
title: Créer une raw string avec un antislash à la fin
uri: Créer-une-raw-string-avec-un-antislash-à-la-fin
url: http://sametmax.com/creer-une-raw-string-avec-un-antislash-a-la-fin/
content:
<p>Si vous vous souvenez, on ne peut pas mettre un antislash à la fin d&#8217;une raw string :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span>r<span style="color: #483d8b;">'Moi pouvoir<span style="color: #000099; font-weight: bold;">\\</span>'</span><span style="color: black;">&#41;</span>
Moi pouvoir\\
<span style="color: #66cc66;">&gt;&gt;&gt;</span> r<span style="color: #483d8b;">'Moi pouvoir<span style="color: #000099; font-weight: bold;">\\</span>'</span>
<span style="color: #483d8b;">'Moi pouvoir<span style="color: #000099; font-weight: bold;">\\</span><span style="color: #000099; font-weight: bold;">\\</span>'</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> r<span style="color: #483d8b;">'Moi pouvoir<span style="color: #000099; font-weight: bold;">\'</span>
  File &quot;&lt;stdin&gt;&quot;, line 1
    r'</span>Moi pouvoir\<span style="color: #483d8b;">'
                  ^
SyntaxError: EOL while scanning string literal</span></pre></div></div>

<p>La plupart du temps on s&#8217;en branle.</p>
<p>Mais supposons que vous vouliez créer un path pour disons, pauvre de vous, une commande DOS&#8230;</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;<span style="color: #000099; font-weight: bold;">\c</span>hemin<span style="color: #000099; font-weight: bold;">\v</span>ers<span style="color: #000099; font-weight: bold;">\d</span>ossier<span style="color: #000099; font-weight: bold;">\d</span>os<span style="color: #000099; font-weight: bold;">\\</span>&quot;</span><span style="color: black;">&#41;</span>
\chemin
        ers\dossier\dos\
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span>r<span style="color: #483d8b;">&quot;<span style="color: #000099; font-weight: bold;">\c</span>hemin<span style="color: #000099; font-weight: bold;">\v</span>ers<span style="color: #000099; font-weight: bold;">\d</span>ossier<span style="color: #000099; font-weight: bold;">\d</span>os<span style="color: #000099; font-weight: bold;">\\</span>&quot;</span><span style="color: black;">&#41;</span>
\chemin\vers\dossier\dos\\</pre></div></div>

<p>Ah, ah, te voilà bien baisé, cher programmeur !</p>
<p>Sauf que non, car une raw string n&#8217;est pas un type de string particulier, comme on l&#8217;a vu ici, donc on peut faire ça :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span>r<span style="color: #483d8b;">&quot;<span style="color: #000099; font-weight: bold;">\c</span>hemin<span style="color: #000099; font-weight: bold;">\v</span>ers<span style="color: #000099; font-weight: bold;">\d</span>ossier<span style="color: #000099; font-weight: bold;">\d</span>os&quot;</span> + <span style="color: #483d8b;">&quot;<span style="color: #000099; font-weight: bold;">\\</span>&quot;</span><span style="color: black;">&#41;</span>
\chemin\vers\dossier\dos\</pre></div></div>

<p>Zooooo !</p>
<p>Et même si on se sent chaud, on peut utiliser la concaténation implicite pour se la jouer mega chaud du slip :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span>r<span style="color: #483d8b;">&quot;<span style="color: #000099; font-weight: bold;">\c</span>hemin<span style="color: #000099; font-weight: bold;">\v</span>ers<span style="color: #000099; font-weight: bold;">\d</span>ossier<span style="color: #000099; font-weight: bold;">\d</span>os&quot;</span> <span style="color: #483d8b;">&quot;<span style="color: #000099; font-weight: bold;">\\</span>&quot;</span><span style="color: black;">&#41;</span>
\chemin\vers\dossier\dos\</pre></div></div>

<p>Qu&#8217;il en faut peu pour qu&#8217;un dev se sente le roi du monde&#8230;</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=7150&amp;md5=c89118a23b9b09aa1a7d137fcb55d01a" title="Flattr" target="_blank"><img src="media/fc229d00.flattr-badge-large.png" data-original-source="http://sametmax.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>


feed_id: http://sametmax.com/?p=7099
title: 20 mg de porn amateur matin et soir
uri: 20-mg-de-porn-amateur-matin-et-soir
url: http://sametmax.com/20-mg-de-porn-amateur-matin-et-soir/
content:
<p style="text-align: center;"><em><small>Ceci est un post invité de <a href="http://sametmax.com/author/golgotha/">golgotha</a> posté sous licence <a href="http://creativecommons.org/licenses/by/3.0/">creative common 3.0 unported</a>.</small></em></p>
<p>On peut objecter aux hommes de trop se décharger devant youjizz (il est où le rouleau de sopalin ??) mais cela a un avantage indéniable&#8230; On acquiert un bac+8 en porn à force d&#8217;étudier les arts de combat des autres mecs, on apprend des techniques plus ou moins efficaces et devenir maître dans l&#8217;art de la galipette n&#8217;est pas chose aisée ! ça ne vient pas comme ça, en claquant des doigts.</p>
<p>Les femmes ayant longtemps été considérée comme des objets pour les hommes, en leur inculquant une morale chrétienne et la culpabilité d’une sexualité libérée, elles doivent aujourd&#8217;hui surmonter ce passé pour apprécier une vidéo porno, qui je le rappelle n’est pas forcément vulgaire. Le truc c&#8217;est que les femmes qui s&#8217;interdisent tout accès à la pornographie pour la simple raison que ce n&#8217;est pas catholique, auront plus de mal d&#8217;une manière général à comprendre ce que désire un homme, par manque de curiosité et par manque d&#8217;expérience, expérience que l&#8217;on peux acquérir justement en allant à droite et à gauche regarder quelques vidéos amateurs. De plus, on voit maintenant fleurir sur les sites des catégories moins hard, plus pour les femmes curieuses de voir quelques vidéos soft genre dimanche soir sur M6.</p>
<p>Exemple  n°1 : je branle mon mec comme un cheval, très vite et très fort, ça va lui faire du bien. WTF, mais arrêtez de nous prendre pour un animal quoi, déjà niveau plaisir ce n&#8217;est pas ça, pire ça peut faire mal ! Un peu de sensualité, de délicatesse, combien de femmes savent qu&#8217;on peut faire jouir un mec sans même le toucher ? Et oui&#8230; Et ça c&#8217;est vraiment un manque de culture érotique, message pour les femmes : Allez regarder du porn !!</p>
<p>Exemple n°2, la pipe mécanique, genre je regonfle mon pneu&#8230; Une bonne fois pour toute : un pipe comme ça, sans regard échangé, de façon mécanique, c&#8217;est ZERO sur l&#8217;échelle du plaisir pour un mec. Désolé de vous décevoir mais ça fait autant d&#8217;effet que de la crème solaire sur le dos d&#8217;une tortue. Pourtant,ce ne sont pas les idées qui manquent, encore une fois le plaisir d&#8217;une pipe sera décuplé par la sensualité, par le jeu amoureux, une femme qui masturbe lentement son mec avec sa bouche juste à coté, qui induit qu&#8217;elle pourrait le lécher sans le lécher, ça c&#8217;est l&#8217;extase pour le mec.</p>
<p>Les femmes : Allez voir du porn amateur (pas des gangbangs pro, ça, ça ne sert à rien), il y a pas mal de vidéos soft et sensuelles qui donnent des idées et surtout qui vous feront changer d&#8217;avis sur la manière de faire bander un mec, parce que vraiment, parfois il y a du boulot&#8230;</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=7099&amp;md5=f54f24f59f011a042e8cb9a9f2045fa3" title="Flattr" target="_blank"><img src="media/fc229d00.flattr-badge-large.png" data-original-source="http://sametmax.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>


feed_id: http://sametmax.com/?p=7172
title: Applatir un iterable like a boss en Python
uri: Applatir-un-iterable-like-a-boss-en-Python
url: http://sametmax.com/applatir-un-iterable-like-a-boss-en-python/
content:
<p>Des structures un peu imbriquées ne sont pas trop difficiles à traiter en Python.</p>
<p>Par exemple, avec une liste en intention imbriquée :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">&gt;&gt;&gt;</span> l = <span style="color: black;">&#91;</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">1</span>, <span style="color: #ff4500;">2</span><span style="color: black;">&#41;</span>, <span style="color: black;">&#40;</span><span style="color: #ff4500;">3</span>, <span style="color: #ff4500;">4</span><span style="color: black;">&#41;</span>, <span style="color: black;">&#40;</span><span style="color: #ff4500;">5</span>, <span style="color: #ff4500;">6</span><span style="color: black;">&#41;</span><span style="color: black;">&#93;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: black;">&#91;</span>y <span style="color: #ff7700;font-weight:bold;">for</span> x <span style="color: #ff7700;font-weight:bold;">in</span> l <span style="color: #ff7700;font-weight:bold;">for</span> y <span style="color: #ff7700;font-weight:bold;">in</span> x<span style="color: black;">&#93;</span>
<span style="color: black;">&#91;</span><span style="color: #ff4500;">1</span>, <span style="color: #ff4500;">2</span>, <span style="color: #ff4500;">3</span>, <span style="color: #ff4500;">4</span>, <span style="color: #ff4500;">5</span>, <span style="color: #ff4500;">6</span><span style="color: black;">&#93;</span></pre></div></div>

<p>Mais quand on a beaucoup de niveaux, par exemple&#8230;</p>
<pre>
a = []
for i in xrange(500):
    a = [a, i]
print(a)

[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[], 0], 1], 2], 3], 4], 5], 6], 7], 8], 9], 10], 11], 12], 13], 14], 15], 16], 17], 18], 19], 20], 21], 22], 23], 24], 25], 26], 27], 28], 29], 30], 31], 32], 33], 34], 35], 36], 37], 38], 39], 40], 41], 42], 43], 44], 45], 46], 47], 48], 49], 50], 51], 52], 53], 54], 55], 56], 57], 58], 59], 60], 61], 62], 63], 64], 65], 66], 67], 68], 69], 70], 71], 72], 73], 74], 75], 76], 77], 78], 79], 80], 81], 82], 83], 84], 85], 86], 87], 88], 89], 90], 91], 92], 93], 94], 95], 96], 97], 98], 99], 100], 101], 102], 103], 104], 105], 106], 107], 108], 109], 110], 111], 112], 113], 114], 115], 116], 117], 118], 119], 120], 121], 122], 123], 124], 125], 126], 127], 128], 129], 130], 131], 132], 133], 134], 135], 136], 137], 138], 139], 140], 141], 142], 143], 144], 145], 146], 147], 148], 149], 150], 151], 152], 153], 154], 155], 156], 157], 158], 159], 160], 161], 162], 163], 164], 165], 166], 167], 168], 169], 170], 171], 172], 173], 174], 175], 176], 177], 178], 179], 180], 181], 182], 183], 184], 185], 186], 187], 188], 189], 190], 191], 192], 193], 194], 195], 196], 197], 198], 199], 200], 201], 202], 203], 204], 205], 206], 207], 208], 209], 210], 211], 212], 213], 214], 215], 216], 217], 218], 219], 220], 221], 222], 223], 224], 225], 226], 227], 228], 229], 230], 231], 232], 233], 234], 235], 236], 237], 238], 239], 240], 241], 242], 243], 244], 245], 246], 247], 248], 249], 250], 251], 252], 253], 254], 255], 256], 257], 258], 259], 260], 261], 262], 263], 264], 265], 266], 267], 268], 269], 270], 271], 272], 273], 274], 275], 276], 277], 278], 279], 280], 281], 282], 283], 284], 285], 286], 287], 288], 289], 290], 291], 292], 293], 294], 295], 296], 297], 298], 299], 300], 301], 302], 303], 304], 305], 306], 307], 308], 309], 310], 311], 312], 313], 314], 315], 316], 317], 318], 319], 320], 321], 322], 323], 324], 325], 326], 327], 328], 329], 330], 331], 332], 333], 334], 335], 336], 337], 338], 339], 340], 341], 342], 343], 344], 345], 346], 347], 348], 349], 350], 351], 352], 353], 354], 355], 356], 357], 358], 359], 360], 361], 362], 363], 364], 365], 366], 367], 368], 369], 370], 371], 372], 373], 374], 375], 376], 377], 378], 379], 380], 381], 382], 383], 384], 385], 386], 387], 388], 389], 390], 391], 392], 393], 394], 395], 396], 397], 398], 399], 400], 401], 402], 403], 404], 405], 406], 407], 408], 409], 410], 411], 412], 413], 414], 415], 416], 417], 418], 419], 420], 421], 422], 423], 424], 425], 426], 427], 428], 429], 430], 431], 432], 433], 434], 435], 436], 437], 438], 439], 440], 441], 442], 443], 444], 445], 446], 447], 448], 449], 450], 451], 452], 453], 454], 455], 456], 457], 458], 459], 460], 461], 462], 463], 464], 465], 466], 467], 468], 469], 470], 471], 472], 473], 474], 475], 476], 477], 478], 479], 480], 481], 482], 483], 484], 485], 486], 487], 488], 489], 490], 491], 492], 493], 494], 495], 496], 497], 498], 499]
</pre>
<p>Là je désactive la coloration syntaxique du blog parce que le snippet à fait planté sublime :-D Heureusement, il reste VI.</p>
<p>Bref, quand on a ce genre de truc, comment on fait ? Pire, comment ont traite un flux de données de types hétérogènes, et dont on ne connait pas la taille, ou de longueur infinie ? C&#8217;est une caractéristique de Python : on a des générateurs plein de duck typing partout !</p>
<p>Voici un petit snippet un peu tordu, mais qui fait des merveilles :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">from</span> <span style="color: #dc143c;">collections</span> <span style="color: #ff7700;font-weight:bold;">import</span> deque, OrderedDict, MutableSet, defaultdict
&nbsp;
&nbsp;
<span style="color: #ff7700;font-weight:bold;">class</span> Flattener<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;"># les types qu'on va applatir, c'est à dire la plupart</span>
    <span style="color: #808080; font-style: italic;"># des iterables sauf les hashmaps</span>
    DEFAULT_FLATTEN_TYPES = <span style="color: black;">&#40;</span>
        <span style="color: #008000;">list</span>,
        <span style="color: #008000;">tuple</span>,
        <span style="color: #008000;">set</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> <span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>.__class__,
        <span style="color: #008000;">xrange</span>,
        deque,
        MutableSet,
    <span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># par défaut, on utilise DEFAULT_FLATTEN_TYPES et</span>
    <span style="color: #808080; font-style: italic;"># aucun iterable_getters (on verra ce que c'est plus bas)</span>
    <span style="color: #808080; font-style: italic;"># puisque c'est le cas le plus courant d'utilisation</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>, flatten_types=<span style="color: #008000;">None</span>, iterable_getters=<span style="color: black;">&#123;</span><span style="color: black;">&#125;</span><span style="color: black;">&#41;</span>:
        <span style="color: #008000;">self</span>.<span style="color: black;">flatten_types</span> = flatten_types <span style="color: #ff7700;font-weight:bold;">or</span> <span style="color: #008000;">self</span>.<span style="color: black;">DEFAULT_FLATTEN_TYPES</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">iterable_getters</span> = iterable_getters
&nbsp;
&nbsp;
    <span style="color: #808080; font-style: italic;"># Retourne True si on doit applatir l'objet.</span>
    <span style="color: #808080; font-style: italic;"># Par défaut, vérifie dans si l'objet est d'un des types</span>
    <span style="color: #808080; font-style: italic;"># DEFAULT_FLATTEN_TYPE.</span>
    <span style="color: #ff7700;font-weight:bold;">def</span> should_flatten<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, obj<span style="color: black;">&#41;</span>:
        <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">isinstance</span><span style="color: black;">&#40;</span>obj, <span style="color: #008000;">self</span>.<span style="color: black;">flatten_types</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># Si avant d'applatir l'objet, l'objet a besoin d'une transformation</span>
    <span style="color: #808080; font-style: italic;"># (par exemple appeler items() sur un dico), on l'applique. </span>
    <span style="color: #808080; font-style: italic;"># Par défaut il n'y a aucune transformation appliquée, quelque soit le </span>
    <span style="color: #808080; font-style: italic;"># type.</span>
    <span style="color: #ff7700;font-weight:bold;">def</span> transform_iterable<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, obj<span style="color: black;">&#41;</span>:
        <span style="color: #ff7700;font-weight:bold;">if</span> obj.__class__ <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">self</span>.<span style="color: black;">iterable_getters</span>:
            <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">self</span>.<span style="color: black;">iterable_getters</span><span style="color: black;">&#91;</span>obj.__class__<span style="color: black;">&#93;</span><span style="color: black;">&#40;</span>obj<span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">return</span> obj
&nbsp;
&nbsp;
    <span style="color: #808080; font-style: italic;"># Permet d'appeler une instance de Flatener, comme si c'était une fonction</span>
    <span style="color: #ff7700;font-weight:bold;">def</span> <span style="color: #0000cd;">__call__</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, iterable<span style="color: black;">&#41;</span>:
        <span style="color: #ff7700;font-weight:bold;">for</span> e <span style="color: #ff7700;font-weight:bold;">in</span>:
            <span style="color: #808080; font-style: italic;"># Si un élément est à applatir, on fait un appel récursif</span>
            <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #008000;">self</span>.<span style="color: black;">should_flatten</span><span style="color: black;">&#40;</span>e<span style="color: black;">&#41;</span>:
                <span style="color: #808080; font-style: italic;"># Appel récursif, et yielding du résultat de cet appel.</span>
                <span style="color: #ff7700;font-weight:bold;">for</span> f <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">self</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>.<span style="color: black;">transform_iterable</span><span style="color: black;">&#40;</span>e<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>:
                    <span style="color: #ff7700;font-weight:bold;">yield</span> f
            <span style="color: #808080; font-style: italic;"># On ne doit pas applatir l'element (genre un int, un str...)</span>
            <span style="color: #808080; font-style: italic;"># donc on le yield directement</span>
            <span style="color: #ff7700;font-weight:bold;">else</span>:
                <span style="color: #ff7700;font-weight:bold;">yield</span> e
&nbsp;
&nbsp;
<span style="color: #808080; font-style: italic;"># fabrique un flattener, ici on prend la config par défaut</span>
flatten = Flattener<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># et pouf</span>
&nbsp;
a = <span style="color: black;">&#91;</span><span style="color: black;">&#93;</span>
<span style="color: #ff7700;font-weight:bold;">for</span> i <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;">500</span><span style="color: black;">&#41;</span>:
    a = <span style="color: black;">&#91;</span>a, i<span style="color: black;">&#93;</span>
&nbsp;
applatie = <span style="color: #008000;">list</span><span style="color: black;">&#40;</span>flatten<span style="color: black;">&#40;</span>a<span style="color: black;">&#41;</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: #008000;">len</span><span style="color: black;">&#40;</span>applatie<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span>applatie<span style="color: black;">&#91;</span>:<span style="color: #ff4500;">10</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span>
<span style="color: #ff4500;">5500</span>
<span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span>, <span style="color: #ff4500;">1</span>, <span style="color: #ff4500;">2</span>, <span style="color: #ff4500;">3</span>, <span style="color: #ff4500;">4</span>, <span style="color: #ff4500;">5</span>, <span style="color: #ff4500;">6</span>, <span style="color: #ff4500;">7</span>, <span style="color: #ff4500;">8</span>, <span style="color: #ff4500;">9</span><span style="color: black;">&#93;</span></pre></div></div>

<p>Ca gère une longeur infinie, et une imbrication de centaines de niveaux. Comme Python a une limite de recursions (1000 par défaut), on est quand même bridé, mais c&#8217;est une situation rare d&#8217;avoir autant de nesting. Et dans les cas extrêmes, on peut allouer une plus grande stack avec <code>sys.setrecursionlimit()</code>.</p>
<p>Via <code>flatten_types</code>, on peut créer différentes politiques d&#8217;applatissement, bien que celle par défaut soit assez saine. Par exemple décider d&#8217;applatir les strings, ou ne pas applatir les tuples : il suffit de passer la bonne liste de types en paramètres. Comme le Flattener est une classe qui permet de créer <code>flatten()</code>, on peut la sous-classer et mettre à disposition plusieurs applatisseurs personnalisés dans sa lib.</p>
<p>La partie :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">                <span style="color: #ff7700;font-weight:bold;">if</span> e.__class__ <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">self</span>.<span style="color: black;">iterable_getters</span>:
                    e = <span style="color: #008000;">self</span>.<span style="color: black;">iterable_getters</span><span style="color: black;">&#91;</span>e.__class__<span style="color: black;">&#93;</span><span style="color: black;">&#40;</span>e<span style="color: black;">&#41;</span></pre></div></div>

<p>Permet de gérer des cas ambigües, comme par exemple les dicos. Comment itérer dessus ? Par clé, par valeur ? Par défaut on ne les applatis pas</p>
<p>On peut par exemple choisir d&#8217;applatir complètement les dictionnaires. :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">a = <span style="color: black;">&#91;</span><span style="color: black;">&#93;</span>
<span style="color: #ff7700;font-weight:bold;">for</span> i <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;">2</span><span style="color: black;">&#41;</span>:
    a = <span style="color: black;">&#91;</span>a, i<span style="color: black;">&#93;</span> + <span style="color: black;">&#91;</span><span style="color: black;">&#123;</span><span style="color: #483d8b;">'a'</span>: <span style="color: #ff4500;">1</span>., <span style="color: #483d8b;">'b'</span>: <span style="color: black;">&#123;</span><span style="color: #483d8b;">'c'</span>: <span style="color: #ff4500;">3</span>.<span style="color: black;">&#125;</span><span style="color: black;">&#125;</span><span style="color: black;">&#93;</span>
<span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span>a<span style="color: black;">&#41;</span>
&nbsp;
<span style="color: black;">&#91;</span><span style="color: black;">&#91;</span><span style="color: black;">&#91;</span><span style="color: black;">&#93;</span>, <span style="color: #ff4500;">0</span>, <span style="color: black;">&#123;</span><span style="color: #483d8b;">'a'</span>: <span style="color: #ff4500;">1.0</span>, <span style="color: #483d8b;">'b'</span>: <span style="color: black;">&#123;</span><span style="color: #483d8b;">'c'</span>: <span style="color: #ff4500;">3.0</span><span style="color: black;">&#125;</span><span style="color: black;">&#125;</span><span style="color: black;">&#93;</span>, <span style="color: #ff4500;">1</span>, <span style="color: black;">&#123;</span><span style="color: #483d8b;">'a'</span>: <span style="color: #ff4500;">1.0</span>, <span style="color: #483d8b;">'b'</span>: <span style="color: black;">&#123;</span><span style="color: #483d8b;">'c'</span>: <span style="color: #ff4500;">3.0</span><span style="color: black;">&#125;</span><span style="color: black;">&#125;</span><span style="color: black;">&#93;</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># on rajoute les dictionnaires aux types à applatir</span>
new_ft = Flattener.<span style="color: black;">DEFAULT_FLATTEN_TYPES</span> + <span style="color: black;">&#40;</span><span style="color: #008000;">dict</span>,<span style="color: black;">&#41;</span>
&nbsp;
dico_flatten = Flattener<span style="color: black;">&#40;</span>flatten_types=new_ft,
                         <span style="color: #808080; font-style: italic;"># on dit qu'un dico rencontré doit être transformé</span>
                         <span style="color: #808080; font-style: italic;"># via items() avant iteration</span>
                         iterable_getters=<span style="color: black;">&#123;</span><span style="color: #008000;">dict</span>: <span style="color: #ff7700;font-weight:bold;">lambda</span> x: x.<span style="color: black;">items</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><span style="color: black;">&#125;</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: #008000;">list</span><span style="color: black;">&#40;</span>dico_flatten<span style="color: black;">&#40;</span>a<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span>, u<span style="color: #483d8b;">'a'</span>, <span style="color: #ff4500;">1.0</span>, u<span style="color: #483d8b;">'b'</span>, u<span style="color: #483d8b;">'c'</span>, <span style="color: #ff4500;">3.0</span>, <span style="color: #ff4500;">1</span>, u<span style="color: #483d8b;">'a'</span>, <span style="color: #ff4500;">1.0</span>, u<span style="color: #483d8b;">'b'</span>, u<span style="color: #483d8b;">'c'</span>, <span style="color: #ff4500;">3.0</span><span style="color: black;">&#93;</span></pre></div></div>

<p>On peut même overrider <code>should_flatten</code> et <code>transform_iterable</code> si des besoins plus importants se font sentir.</p>
<p>Attention tout de même à ce que vous mettez dans <code>flatten_types</code>. Par exemple, une string d&#8217;un caractère est à la fois yieldable comme valeur et itérable, ce qui va provoquer une recursion infinie. Adaptez toujours <code>iterable_getters</code> en conséquence.</p>
<p>Hop, dans <a href="sametmax.com/batbelt-la-lib-des-petits-outils-python-qui-vont-bien/">batbelt</a>.</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=7172&amp;md5=bf45308d8818fd8b16ef26b0e01e93b9" title="Flattr" target="_blank"><img src="media/fc229d00.flattr-badge-large.png" data-original-source="http://sametmax.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>


feed_id: http://sametmax.com/?p=7165
title: PYTHON, WHY U NO HAZ A SIGN FUNCTION ?
uri: PYTHON-WHY-U-NO-HAZ-A-SIGN-FUNCTION
url: http://sametmax.com/python-why-u-no-haz-a-sign-function/
content:
<p>Bien que Python soit un langage massivement utilisé par la communauté scientifique, la lib standard ne contient pas de fonction aussi simple que <code>sign()</code>. Et on voit ça et là des libs qui contiennent quelque chose comme ça:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">def</span> sign<span style="color: black;">&#40;</span>x<span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">if</span> x <span style="color: #66cc66;">&gt;</span> <span style="color: #ff4500;">0</span>:
        <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #ff4500;">1</span>
    <span style="color: #ff7700;font-weight:bold;">if</span> x == <span style="color: #ff4500;">0</span>:
        <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #ff4500;">0</span>
    <span style="color: #ff7700;font-weight:bold;">return</span> -<span style="color: #ff4500;">1</span>
&nbsp;
<span style="color: #66cc66;">&gt;&gt;&gt;</span> sign<span style="color: black;">&#40;</span><span style="color: #ff4500;">3</span><span style="color: black;">&#41;</span>
<span style="color: #ff4500;">1</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> sign<span style="color: black;">&#40;</span>-<span style="color: #ff4500;">3</span><span style="color: black;">&#41;</span>
-<span style="color: #ff4500;">1</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> sign<span style="color: black;">&#40;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#41;</span>
<span style="color: #ff4500;">0</span></pre></div></div>

<p>Comme <a href="http://sametmax.com/pourquoi-join-en-python/">d&#8217;autres de choix étonnants</a> dans l&#8217;architecture de Python, il y a une raison raisonnablement raisonnable : il n&#8217;existe aucun standard sur ce que doit faire une telle fonction dans les cas ambigües.</p>
<p>En effet, que doit faire la fonction avec <code>NaN</code> ? Avec un complexe ?</p>
<p>Il y a eu un débat sur ce qu&#8217;il faut faire dans ce cas, et <a href="http://bugs.python.org/msg59137">un consensus n&#8217;a PAS été trouvé</a>.</p>
<p>Par contre, il existe <a href="http://en.wikipedia.org/wiki/IEEE_floating_point">un standard international</a> définissant une autre opération : celle de copier un signe. Elle a donc été implémentée :</p>

<div class="wp_syntax"><div 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> <span style="color: #dc143c;">math</span> <span style="color: #ff7700;font-weight:bold;">import</span> copysign
<span style="color: #66cc66;">&gt;&gt;&gt;</span> copysign<span style="color: black;">&#40;</span><span style="color: #ff4500;">10</span>, -<span style="color: #ff4500;">3</span><span style="color: black;">&#41;</span>
-<span style="color: #ff4500;">10.0</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> copysign<span style="color: black;">&#40;</span><span style="color: #ff4500;">10</span>, <span style="color: #ff4500;">22</span><span style="color: black;">&#41;</span>
<span style="color: #ff4500;">10.0</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> copysign<span style="color: black;">&#40;</span><span style="color: #ff4500;">10</span>, <span style="color: #008000;">float</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'-NaN'</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
-<span style="color: #ff4500;">10</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> copysign<span style="color: black;">&#40;</span><span style="color: #ff4500;">10</span>, -2j<span style="color: black;">&#41;</span>
Traceback <span style="color: black;">&#40;</span>most recent call last<span style="color: black;">&#41;</span>:
  File <span style="color: #483d8b;">&quot;&lt;ipython-input-13-ece93d1317dc&gt;&quot;</span>, line <span style="color: #ff4500;">1</span>, <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #66cc66;">&lt;</span>module<span style="color: #66cc66;">&gt;</span>
    copysign<span style="color: black;">&#40;</span><span style="color: #ff4500;">10</span>, -2j<span style="color: black;">&#41;</span>
<span style="color: #008000;">TypeError</span>: can<span style="color: #483d8b;">'t convert complex to float</span></pre></div></div>

<p>Copier le signe n&#8217;est pas la même chose que de retourner quelque chose selon le signe, et donc sémantiquement, choisir quoi retourner était plus facile. Comme la plupart du temps, on veut récupérer <code>-1</code> ou <code>1</code> pour le multiplier avec quelque chose et justement copier le signe, cela résolvait pas mal de problèmes.</p>
<p>Mais même dans le rare cas où on a besoin du résultat que renverrait <code>sign()</code>, il est très facile à obtenir en une ligne :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">&gt;&gt;&gt;</span> mon_nombre = <span style="color: #ff4500;">3</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> mon_nombre <span style="color: #ff7700;font-weight:bold;">and</span> copysign<span style="color: black;">&#40;</span><span style="color: #ff4500;">1</span>, mon_nombre<span style="color: black;">&#41;</span>
<span style="color: #ff4500;">1.0</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> mon_nombre = -<span style="color: #ff4500;">3</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> mon_nombre <span style="color: #ff7700;font-weight:bold;">and</span> copysign<span style="color: black;">&#40;</span><span style="color: #ff4500;">1</span>, mon_nombre<span style="color: black;">&#41;</span>
-<span style="color: #ff4500;">1.0</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> mon_nombre = <span style="color: #ff4500;">0</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> mon_nombre <span style="color: #ff7700;font-weight:bold;">and</span> copysign<span style="color: black;">&#40;</span><span style="color: #ff4500;">1</span>, mon_nombre<span style="color: black;">&#41;</span>
<span style="color: #ff4500;">0</span></pre></div></div>

<p>Et pour ce cas de figure, les retours sur des valeurs ambigües sont laissés à la charge du codeur.</p>
<p>P.S: je sais qu&#8217;il y a des exemples sur le net montrant <code>cmp(0, mon_nombre)</code> pour obtenir la même fonctionnalité. Sachez que <code>cmp</code> a été retirée de Python 3, donc faites attention si vous l&#8217;utilisez.</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=7165&amp;md5=77f721f581bfec1a4620c86be0e805ee" title="Flattr" target="_blank"><img src="media/fc229d00.flattr-badge-large.png" data-original-source="http://sametmax.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>


feed_id: http://sametmax.com/?p=7190
title: Demande d&#8217;aide via le formulaire de contact
uri: Demande-d-aide-via-le-formulaire-de-contact
url: http://sametmax.com/demande-daide-via-le-formulaire-de-contact/
content:
<p>On reçoit de plus en plus de demandes d&#8217;aide via le formulaire de contact, et à chaque fois on y a répondu autant que possible, mais en y ajoutant le commentaire suivant :</p>
<h2>Les mails ne sont pas un bon moyen de chercher de l&#8217;aide.</h2>
<p>D&#8217;abord, cela prend beaucoup de temps pour nous de lire, résoudre et répondre à votre problématique. </p>
<p>Ensuite, c&#8217;est du un par un, et personne d&#8217;autre que vous ne profite de la réponse. A moins qu&#8217;on prenne ENCORE plus de temps pour faire un résumé sur le blog.</p>
<p>Et puis il y a le formatage du mail qui est à chier pour le code, le fait que l&#8217;historique soit moins clair que sur d&#8217;autres support, le fait qu&#8217;on ne bénéficie pas de l&#8217;aide en commentaires (car oui, nos lecteurs nous aident).</p>
<p>Mais surtout&#8230;</p>
<h2>il y a d&#8217;autres endroits pour ça</h2>
<ul>
<li>Pour Django, il y a le <a href="http://forum.django-fr.org/">forum de Django-fr</a>.</li>
<li>Pour Python, il y a le <a href="http://www.afpy.org/forums/forum_python">forum de l&#8217;afpy</a>.</li>
<li>Pour à peu près tout, il y a l&#8217;exceptionnel <a href="http://stackoverflow.com/">Stackoverflow</a>.</li>
</ul>
<p>Honnêtement, si vous ne trouvez pas ce que vous cherchez sur ces supports, il y a peu de chance que nous ayons la réponse de toute façon.</p>
<p>Alors je sais, le forum de Django-fr a un design des années 90, et celui de l&#8217;afpy est la négation même de l&#8217;ergonomie. On a plusieurs fois réfléchi à ouvrir une sorte de forum nous-même, mais on a mis en stand by. Manque de courage.</p>
<p>Bref, le formulaire de contact, gardez-le pour : les questions non techniques, les compliments et insultes, les signalements et partages, les demandes d&#8217;article, etc.</p>
<h2>Une SEULE exception :</h2>
<p><a href="http://sametmax.com/notre-programme-envoyez-nous-les-scripts-que-vous-ne-pigez-pas-est-toujours-dactu/">Envoyez nous les scripts que vous ne pigez pas</a>.</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=7190&amp;md5=af14ac7ff29f44d9225492cbb62b9928" title="Flattr" target="_blank"><img src="media/fc229d00.flattr-badge-large.png" data-original-source="http://sametmax.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>


feed_id: http://sametmax.com/?p=7158
title: Échange de liens, article publicitaire et autres requêtes marketing
uri: Échange-de-liens-article-publicitaire-et-autres-requêtes-marketing
url: http://sametmax.com/echange-de-lien-article-publitaire-et-autre-requetes-marketting/
content:
<p>On reçoit parfois des mails de ce genre :</p>
<blockquote><p>Subject: Parler de notre site</p>
<p>Message Body:<br />
Bonjour,</p>
<p>Nous aimerions parler de notre site [censored] sur http://sametmax.com/, est-ce envisageable ? De notre coté on peut publier un article sur ton site, en parler sur notre page facebook (380,000 fans), ou autre. Qu’en penses tu ?</p>
<p>Cordialement,
</p></blockquote>
<p>La réponse est non. </p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=7158&amp;md5=0c30c3d5ee55394063d724784123e981" title="Flattr" target="_blank"><img src="media/fc229d00.flattr-badge-large.png" data-original-source="http://sametmax.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>


feed_id: http://sametmax.com/?p=7218
title: Connaissez vous l&#8217;objet slice en Python ?
uri: Connaissez-vous-l-objet-slice-en-Python
url: http://sametmax.com/connaissez-vous-lobjet-slice-en-python/
content:
<p>Python, le langage sans fond. Arriverai-je à n&#8217;avoir plus jamais d&#8217;article à écrire un jour ?</p>
<p>Tenez, hier, j&#8217;étais en train de lire un blog sur le Web, le bourrelet paresseusement calé entre mon dossier et la table, quand soudain, boum !</p>
<p>Je tombe sur ça :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #008000;">slice</span>
<span style="color: #66cc66;">&lt;</span>type <span style="color: #483d8b;">'slice'</span><span style="color: #66cc66;">&gt;</span></pre></div></div>

<p>Aucun import. Rien. </p>
<p>Attend, il y a un type built-in <code>slice</code> en Python ? What the actual fucking fuck ?</p>
<p>Alors je testouille un truc, y croyant vaguement :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">&gt;&gt;&gt;</span> lst = <span style="color: black;">&#91;</span><span style="color: #483d8b;">'a'</span>, <span style="color: #483d8b;">'b'</span>, <span style="color: #483d8b;">'c'</span>, <span style="color: #483d8b;">'d'</span><span style="color: black;">&#93;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> lst<span style="color: black;">&#91;</span><span style="color: #ff4500;">1</span>:<span style="color: #ff4500;">3</span><span style="color: black;">&#93;</span>
<span style="color: black;">&#91;</span>u<span style="color: #483d8b;">'b'</span>, u<span style="color: #483d8b;">'c'</span><span style="color: black;">&#93;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> lst<span style="color: black;">&#91;</span><span style="color: #008000;">slice</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">1</span>,<span style="color: #ff4500;">3</span><span style="color: black;">&#41;</span><span style="color: black;">&#93;</span>
<span style="color: black;">&#91;</span>u<span style="color: #483d8b;">'b'</span>, u<span style="color: #483d8b;">'c'</span><span style="color: black;">&#93;</span></pre></div></div>

<p>Donc plutôt que de se trimbaler avec des tuples de valeurs dont il faudra tester ou imposer la taille. Plutôt que d&#8217;attendre en paramètre uniquement des entiers positionnels ou forcer le passage de None, on peut aussi tout simplement passer un slice à vos fonctions qui font du slicing.</p>
<p>Ça veut dire des objets slices en valeurs par défaut.</p>
<p>Ça veut dire des objets slices dans les mapping, les iterables, etc.</p>
<p>Un seul regret :</p>

<div class="wp_syntax"><div 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> <span style="color: #dc143c;">itertools</span> <span style="color: #ff7700;font-weight:bold;">import</span> islice
<span style="color: #66cc66;">&gt;&gt;&gt;</span> islice<span style="color: black;">&#40;</span>lst, <span style="color: #008000;">slice</span><span style="color: black;">&#41;</span>
Traceback <span style="color: black;">&#40;</span>most recent call last<span style="color: black;">&#41;</span>:
  File <span style="color: #483d8b;">&quot;&lt;ipython-input-5-7eb2c7533070&gt;&quot;</span>, line <span style="color: #ff4500;">1</span>, <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #66cc66;">&lt;</span>module<span style="color: #66cc66;">&gt;</span>
    islice<span style="color: black;">&#40;</span>lst, <span style="color: #008000;">slice</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">1</span>,<span style="color: #ff4500;">3</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
<span style="color: #008000;">ValueError</span>: Stop argument <span style="color: #ff7700;font-weight:bold;">for</span> islice<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span> must be <span style="color: #008000;">None</span> <span style="color: #ff7700;font-weight:bold;">or</span> an integer: <span style="color: #ff4500;">0</span> <span style="color: #66cc66;">&lt;</span>= x <span style="color: #66cc66;">&lt;</span>= maxint.</pre></div></div>

<p>Et ça c&#8217;est vraiment con.</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=7218&amp;md5=74d92772551315fbc90e84d0e1797bf0" title="Flattr" target="_blank"><img src="media/fc229d00.flattr-badge-large.png" data-original-source="http://sametmax.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>


feed_id: http://sametmax.com/?p=7209
title: Style CSS du blog pour les créatures nocturnes
uri: Style-CSS-du-blog-pour-les-créatures-nocturnes
url: http://sametmax.com/style-css-du-blog-pour-les-creatures-nocturnes/
content:
<p style="text-align: center;"><em><small>Ceci est un post invité de <a href="http://sametmax.com/author/cactus/">cactus</a> posté sous licence <a href="http://creativecommons.org/licenses/by/3.0/">creative common 3.0 unported</a>.</small></em></p>
<p>Comme tout bon codeur, je travaille la nuit ou alors la journée mais seulement avec les volets fermés.<br />
Et si y&#8217;a bien un défaut avec ce blog, c&#8217;est qu&#8217;il arrache la rétine à la pince anglaise !<br />
Du coup, de mes petits doigts agiles et gracieux je me suis bricolé un petit CSS maison pour ne plus pleurer chaque fois que j&#8217;ai besoin de relire un des articles, en rendant le site ténébreux plus qu&#8217;un gothique un soir sans lune !<br />
Comme vous pouvez le constater, la différence est flagrante :<br />
<div id="attachment_7210" class="wp-caption aligncenter" style="width: 450px"><a href="http://sametmax.com/style-css-du-blog-pour-les-creatures-nocturnes/semcomp/" rel="attachment wp-att-7210"><img src="media/01a6a510.semcomp.jpeg" data-original-source="http://sametmax.com/wp-content/uploads/2013/08/semcomp.jpeg" alt="Le Paradis domine l&#039;Enfer !" title="Une mariée qui chevauche une sacrée BBC !" width="440" height="482" class="size-full wp-image-7210" /></a><p class="wp-caption-text">S&#038;M : comparaison entre sans et avec thème</p></div></p>
<p>Pour l&#8217;appliquer, j&#8217;utilise l&#8217;extension Stylish de mon navigateur (l&#8217;addon est disponible pour tous les navigateurs populaires).<br />
Voici donc le style :</p>

<div class="wp_syntax"><div class="code"><pre class="css" style="font-family:monospace;"><span style="color: #a1a100;">@namespace url(http://www.w3.org/1999/xhtml);</span>
<span style="color: #a1a100;">@-moz-document domain(&quot;sametmax.com&quot;) {</span>
	body <span style="color: #00AA00;">&#123;</span>
		<span style="color: #000000; font-weight: bold;">background</span><span style="color: #00AA00;">:</span> <span style="color: #993333;">none</span> !important<span style="color: #00AA00;">;</span>
		<span style="color: #000000; font-weight: bold;">background-color</span><span style="color: #00AA00;">:</span> <span style="color: #000000; font-weight: bold;">black</span> !important<span style="color: #00AA00;">;</span>
		<span style="color: #000000; font-weight: bold;">color</span><span style="color: #00AA00;">:</span> <span style="color: #993333;">white</span> !important<span style="color: #00AA00;">;</span>
	<span style="color: #00AA00;">&#125;</span> code<span style="color: #00AA00;">,</span> pre<span style="color: #00AA00;">,</span> blockquote <span style="color: #00AA00;">&#123;</span>
		<span style="color: #000000; font-weight: bold;">background-color</span> <span style="color: #00AA00;">:</span> <span style="color: #cc00cc;">#101010</span> !important<span style="color: #00AA00;">;</span>
		<span style="color: #000000; font-weight: bold;">color</span> <span style="color: #00AA00;">:</span> <span style="color: #993333;">white</span> !important<span style="color: #00AA00;">;</span>
	<span style="color: #00AA00;">&#125;</span> <span style="color: #cc00cc;">#slogan</span> <span style="color: #00AA00;">&#123;</span>
		<span style="color: #000000; font-weight: bold;">color</span><span style="color: #00AA00;">:</span> <span style="color: #993333;">white</span> !important<span style="color: #00AA00;">;</span>
	<span style="color: #00AA00;">&#125;</span> a <span style="color: #00AA00;">&#123;</span>
		<span style="color: #000000; font-weight: bold;">color</span><span style="color: #00AA00;">:</span> grey !important<span style="color: #00AA00;">;</span>
	<span style="color: #00AA00;">&#125;</span> <span style="color: #cc00cc;">#header</span> ul li <span style="color: #00AA00;">&#123;</span>
		<span style="color: #000000; font-weight: bold;">color</span><span style="color: #00AA00;">:</span> <span style="color: #993333;">white</span> !important<span style="color: #00AA00;">;</span>
		<span style="color: #000000; font-weight: bold;">background-color</span><span style="color: #00AA00;">:</span> <span style="color: #cc00cc;">#101010</span> !important<span style="color: #00AA00;">;</span>
	<span style="color: #00AA00;">&#125;</span> ul<span style="color: #6666ff;">.nav</span> li<span style="color: #3333ff;">:hover </span>a <span style="color: #00AA00;">&#123;</span>
		<span style="color: #000000; font-weight: bold;">background-color</span><span style="color: #00AA00;">:</span> <span style="color: #cc00cc;">#202020</span> !important<span style="color: #00AA00;">;</span>
	<span style="color: #00AA00;">&#125;</span> <span style="color: #cc00cc;">#header</span> ul <span style="color: #00AA00;">&#123;</span>
		<span style="color: #000000; font-weight: bold;">background-color</span><span style="color: #00AA00;">:</span> <span style="color: #000000; font-weight: bold;">black</span> !important<span style="color: #00AA00;">;</span>
	<span style="color: #00AA00;">&#125;</span> <span style="color: #00AA00;">*</span> <span style="color: #00AA00;">&#123;</span>
		<span style="color: #000000; font-weight: bold;">text-shadow</span><span style="color: #00AA00;">:</span> <span style="color: #993333;">none</span> !important<span style="color: #00AA00;">;</span>
	<span style="color: #00AA00;">&#125;</span>
<span style="color: #00AA00;">&#125;</span></pre></div></div>

<p>Pour pousser un peu plus loin il y a le problème de la coloration syntaxique. En effet, le style est codé directement dans les balises html, qui ne sont pas modifiées par le CSS, et la coloration syntaxique foire parfois. Du coup pour ceux qui veulent se montrer tatillons, il faut utiliser un petit script (à intégrer par exemple à GreaseMonkey) pour modifier la coloration syntaxique.<br />
Voilà le script :</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;"><span style="color: #006600; font-style: italic;">// ==UserScript==</span>
<span style="color: #006600; font-style: italic;">// @name        Sam&amp;Max - Litlle Color Fix</span>
<span style="color: #006600; font-style: italic;">// @namespace   sametmax.com</span>
<span style="color: #006600; font-style: italic;">// @description Fix a color bug for code coloring on sametmax.com with Stylish &quot;Darker&quot; theme</span>
<span style="color: #006600; font-style: italic;">// @include     http://sametmax.com/*</span>
<span style="color: #006600; font-style: italic;">// @version     1</span>
<span style="color: #003366; font-weight: bold;">var</span> spans <span style="color: #339933;">=</span> document.<span style="color: #660066;">getElementsByTagName</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;span&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
console.<span style="color: #660066;">info</span><span style="color: #009900;">&#40;</span>spans.<span style="color: #660066;">length</span> <span style="color: #339933;">+</span> <span style="color: #3366CC;">&quot; spans trouvés by GreaseMonkey/Sam&amp;Max - Little Color Fix&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #003366; font-weight: bold;">var</span> white <span style="color: #339933;">=</span> <span style="color: #CC0000;">0</span><span style="color: #339933;">;</span>
<span style="color: #000066; font-weight: bold;">for</span> <span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">var</span> i<span style="color: #339933;">=</span><span style="color: #CC0000;">0</span><span style="color: #339933;">;</span> i <span style="color: #339933;">&lt;</span> spans.<span style="color: #660066;">length</span><span style="color: #339933;">;</span> i<span style="color: #339933;">++</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
	<span style="color: #000066; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>spans<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span>.<span style="color: #660066;">style</span>.<span style="color: #660066;">color</span> <span style="color: #339933;">==</span> <span style="color: #3366CC;">&quot;black&quot;</span> <span style="color: #339933;">||</span> spans<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span>.<span style="color: #660066;">style</span>.<span style="color: #660066;">color</span> <span style="color: #339933;">==</span> <span style="color: #3366CC;">&quot;#000000&quot;</span> <span style="color: #339933;">||</span> spans<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span>.<span style="color: #660066;">style</span>.<span style="color: #660066;">color</span> <span style="color: #339933;">==</span> <span style="color: #3366CC;">&quot;rgb(0, 0, 0)&quot;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
		spans<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span>.<span style="color: #660066;">style</span>.<span style="color: #660066;">color</span> <span style="color: #339933;">=</span> <span style="color: #3366CC;">&quot;white&quot;</span><span style="color: #339933;">;</span>
		white<span style="color: #339933;">++;</span>
	<span style="color: #009900;">&#125;</span>
	<span style="color: #000066; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>spans<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span>.<span style="color: #660066;">style</span>.<span style="color: #660066;">color</span> <span style="color: #339933;">==</span> <span style="color: #3366CC;">&quot;#000000&quot;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
		spans<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span>.<span style="color: #660066;">style</span>.<span style="color: #660066;">color</span> <span style="color: #339933;">=</span> <span style="color: #3366CC;">&quot;blue&quot;</span><span style="color: #339933;">;</span>
	<span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span>
console.<span style="color: #660066;">info</span><span style="color: #009900;">&#40;</span>white <span style="color: #339933;">+</span> <span style="color: #3366CC;">&quot; spans colorisés by GreaseMonkey/Sam&amp;Max - Little Color Fix&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #006600; font-style: italic;">// ==/UserScript==</span></pre></div></div>

<p>Enfin, pour ceux qui se plaignent qu&#8217;il y ait du cul dans les articles de SM, un petit Stylish pour enlever les images :</p>

<div class="wp_syntax"><div class="code"><pre class="css" style="font-family:monospace;"><span style="color: #a1a100;">@namespace url(http://www.w3.org/1999/xhtml);</span>
<span style="color: #a1a100;">@-moz-document domain(&quot;sametmax.com&quot;) {</span>
	<span style="color: #6666ff;">.wp-caption</span><span style="color: #00AA00;">,</span> <span style="color: #6666ff;">.wp-post-image</span> <span style="color: #00AA00;">&#123;</span><span style="color: #000000; font-weight: bold;">visibility</span><span style="color: #00AA00;">:</span> <span style="color: #993333;">hidden</span> !important<span style="color: #00AA00;">;</span><span style="color: #00AA00;">&#125;</span>
<span style="color: #00AA00;">&#125;</span></pre></div></div>

 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=7209&amp;md5=e6376bd1b1f88b82dea431b7d924d52c" title="Flattr" target="_blank"><img src="media/fc229d00.flattr-badge-large.png" data-original-source="http://sametmax.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>


feed_id: http://sametmax.com/?p=7229
title: Moi de septembre off
uri: Moi-de-septembre-off
url: http://sametmax.com/moi-de-septembre-off/
content:
<p>Ce mois de septembre, je ne serai pas sur le blog.</p>
<p>Je vous laisserai donc avec Max.</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=7229&amp;md5=e9746cb059bdc7ba3433dc30d1b93a03" title="Flattr" target="_blank"><img src="media/fc229d00.flattr-badge-large.png" data-original-source="http://sametmax.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>


feed_id: http://sametmax.com/?p=7235
title: Servir les fichiers statiques Django avec un .htaccess Apache
uri: Servir-les-fichiers-statiques-Django-avec-un-httaccess-Apache
url: http://sametmax.com/servir-les-fichiers-statiques-django-avec-un-httaccess-apache/
content:
<p>Servir le Javascript, les images et le CSS avec Django a toujours été une grande question pour les débutants.</p>
<p>J&#8217;avais fais un giga article pour expliquer <a href="http://sametmax.com/comment-servir-les-fichiers-statiques-avec-django-en-dev-et-en-prod/">comment servir les fichiers statiques avec ce framework</a>, mais j&#8217;ai réalisé ensuite que les gens n&#8217;avaient pas forcément accès aux fichiers de configuration du serveur.</p>
<p>Parfois, tout ce qu&#8217;ils ont c&#8217;est un pauvre fichier <em>.htaccess</em>. Tout n&#8217;est pas perdu, avec une petite règle de rewrite :</p>
<pre>AddHandler fcgid-script .fcgi
RewriteEngine On
RewriteRule /static/ /chemin/vers/dossier/racine/apache/static
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ site.fcgi/$1 [QSA,L]</pre>
<p>Attention à ce que <em>/static/</em> corresponde bien à l&#8217;arborescence <strong>complète</strong> de sous dossiers de <em>/chemin/vers/dossier/racine/apache/</em> et à <code>settings.STATIC_ROOT</code>.</p>
<p>Par exemple :</p>
<pre>AddHandler fcgid-script .fcgi
RewriteEngine On
RewriteRule /sous/dossier/static/ /chemin/vers/dossier/racine/apache/sous/dossier/static
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ site.fcgi/$1 [QSA,L]</pre>
<p>Et <code>settings.STATIC_ROOT = "/sous/dossier/static/"</code>.</p>
<p>En effet, on fait un rewrite ici, on ne sert pas le sous dossier directement.</p>
<p>P.S: ça va sans le dire, mais ça va mieux en le disant, c&#8217;est de la prod, donc faut faire un <code>manage.py collecstatic</code> avant, et s&#8217;assurer d&#8217;avoir les bonnes valeurs pour <code>settings.STATIC_ROOT</code> et <code>settings.STATIC_URL</code>/</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=7235&amp;md5=ecd3aa8b126ad5683cd47a723611ae5a" title="Flattr" target="_blank"><img src="media/fc229d00.flattr-badge-large.png" data-original-source="http://sametmax.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>


feed_id: http://sametmax.com/?p=7244
title: Sol, do, mi, Sol, do, mi, Sol, do, mi
uri: Sol-do-mi-Sol-do-mi-Sol-do-mi
url: http://sametmax.com/sol-do-mi-sol-do-mi-sol-do-mi/
content:
<p>Le rectum n&#8217;étant pas lubrifié et prévu initialement pour la sortie, et non l&#8217;entrée, la sodomie demande un peu plus de travail que la pénétration vaginale.</p>
<p>En fait, même quand vous voyez une actrice faire ça en deux, deux :</p>

<!-- iframe plugin v:2.3 - wordpress.org/extend/plugins/iframe/ -->
<iframe src="http://www.youjizz.com/videos/embed/2211811" frameborder="0" width="560" height="440" scrolling="no" allowtransparency="true" class="iframe-class"></iframe>
<p>Derrière, elle s&#8217;est préparée hors caméra.</p>
<p>Déjà, il y a peu de nanas qui ont envie, ou même acceptent, de se faire prendre sans préliminaire, trou-du-cul ou pas. Ça arrive, mais c&#8217;est circonstanciel. J&#8217;exclus évidement les pros qui sont là pour vous satisfaire, et donc qui seront prêtes à votre arrivée.</p>
<p>En plus pour le fion, si vous avez déjà mis un thermomètre ou un supo, vous savez que c&#8217;est une zone sensible. Imaginez donc faire rentrer une carotte, une banane, voir pour les plus africains d&#8217;entre nous, un concombre.</p>
<p>Si vous y allez directe, ça risque de tout simplement pas rentrer. Ou alors de casser. Un anus qui saigne, à l&#8217;exception de jeux SM, c&#8217;est la fin des galipettes.</p>
<p>Supposons donc que votre partenaire fasse parti de cette minorité qui accepte de se prendre une bite dans le derrière, ou, plus rare encore, qui aime ça.</p>
<h2>Protocole</h2>
<ol>
<li>Lubrifier. Lubrifier. Lubrifier. La sodo à sec, c&#8217;est à réserver au SM. La salive seule, je ne recommande pas, même si c&#8217;est mieux que rien. Les produits qu&#8217;il y a sur les capotes ne suffisent pas. Il va falloir investir. Souvenez-vous que la vaseline ou l&#8217;huile de coco, qui marchent très bien, ne sont pas compatibles avec les préservatifs. On trouvent des gels acqueux en grande surface maintenant.</li>
<li>Mettez une dose sur le bord de l&#8217;anus, et une dose sur tout ce que vous allez faire rentrer.</li>
<li>Commencez petit : l&#8217;auriculaire (avec les ongles bien coupés) ou un mini-gode, de préférence en verre ou en métal, pas en pastique ou latex si possible, ça glisse mieux. Le gode est généralement mieux que le doigt, mais on a pas toujours ça sous la main.</li>
<li>N&#8217;insérez pas tout de suite : titillez les abords, jouez avec. Idéalement, commencez en parallèle à une autre stimulation : en pleine baise, cuni, doitage, etc.</li>
<li>Première insertion, 1 cm, max. Plutôt que d&#8217;enfoncer, tournez un peu, poussez les bords, écartez par rotation afin de relaxer la zone et élargir l&#8217;entrée. Si vous avez un doute, mettez-vous le même chose dans le cul, votre perspective va tout de suite s&#8217;élargir :-)</li>
<li>Petit à petit, progressez plus loin jusqu&#8217;à arriver au max de votre outil actuel. Puis passez à une taille plus grosse, et recommencez à l&#8217;étape précédente. Jusqu&#8217;à ce que l&#8217;objet en question soi votre queue, ce qui est quand même l&#8217;objectif.</li>
</ol>
<p>Sinon vous avez l&#8217;autre technique, qui consiste à prendre la meuf par les cheveux et l&#8217;enculer d&#8217;un coup contre un mur. Ça passe avec les pros, les soumises, les filles qui adorent la sodomie et qui sont déjà très excitées, ou celles que vous ne voulez jamais revoir.</p>
<h2>Position</h2>
<p>Il est très excitant pour le mec de pratiquer la sodo par derrière, mais si votre meuf n&#8217;est pas habituée, c&#8217;est plus dur, du fait de la forme du colon. La position dans laquelle ça rentre le mieux, c&#8217;est la position du missionnaire. C&#8217;est contre-intuitif, mais le pénis est généralement bandé en arc, et cet arc ira ainsi dans le sens du tuyau dans lequel vous voulez le faire rentrer. Pensez-y pour les premières fois.</p>
<p>Je ne recommande pas l&#8217;andromaque, ça prendra 3 heures avec une débutante effarouchée, à moins que vous soyez très, très patient.</p>
<p>À l&#8217;inverse, si vous êtes très à l&#8217;aise, la levrette permet plus facilement de mettre un gode dans la chatte en même temps (ou la fameuse banane chaude de La cité de Dieu ^^), et c&#8217;est là qu&#8217;on s&#8217;amuse vraiment. Je n&#8217;ai jamais essayé la double pénétration avec deux personnes, donc je ne peux pas vous aiguiller sur ce point, je laisse pour ça la parole à Max. Gageons qu&#8217;il a une approche plus directe que la mienne. Je suppose simplement que du coup, préparer avec une bite derrière et un gode devant est envisageable.</p>
<h2>A quoi s&#8217;attendre</h2>
<p>Si vous croyez que la sodo, c&#8217;est propre comme dans les films, vous n&#8217;avez pas vraiment compris l&#8217;usage métabolique primaire de cette partie de l&#8217;anatomie. C&#8217;est un trou à merde.</p>
<p>Donc, attendez-vous à voir de la merde. Logique.</p>
<p>Quand c&#8217;est planifié, et avec des habitué(e)s (car pour le coup, l&#8217;article marche pour les gays), la personne qui reçoit&#8230; C&#8217;est comme ça qu&#8217;on appelle l&#8217;enculé(e) dans les milieux autorisés : la personne qui reçoit. La personne qui reçoit, donc, se prépare parfois avant, par exemple en faisant un lavement.</p>
<p>Mais vous ne serez probablement pas dans ce cas là.</p>
<p>Donc, merde.</p>
<p>Des traces sur votre penis, mais aussi parfois tout un morceau qui peut sortir une fois que vous l&#8217;avez retiré.</p>
<p>Des pets également.</p>
<p>Ca dépend pas mal de ce que la digestion d&#8217;autruit pour le coup, et du moment de la pénétration.</p>
<p>Et aussi parfois le fameux <a href="http://www.urbandictionary.com/define.php?term=santorum">santorum </a>. Je n&#8217;en ai jamais vu, mais il parait que ça existe.</p>
<p>Bref, ça ne ressemblera pas à ça :</p>

<!-- iframe plugin v:2.3 - wordpress.org/extend/plugins/iframe/ -->
<iframe width="510" height="400" src="http://xhamster.com/xembed.php?video=2103610" frameborder="0" scrolling="no" class="iframe-class"></iframe>
<h2>Contusion</h2>
<p>Le colon est un organe très peu inervé. Comprenez par là que les sensations ressenties à ce niveau sont très faibles. Donc, si la personne vous dit d&#8217;arrêter, vous arrêtez. Parce que si elle ressent une sensation désagréable au niveau du colon, c&#8217;est que c&#8217;est que quelque chose d&#8217;important se passe. Oui, on peut percer le tuyau. C&#8217;est pas courant, mais c&#8217;est possible. Dans tous les cas on peut gravement l&#8217;irriter. Donc pour que le cul reste un jeu, soyez fair play, ne faites pas l&#8217;enculé avec votre enculé(e).</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=7244&amp;md5=d59eb1a73455897f70899b5a62922e30" title="Flattr" target="_blank"><img src="media/fc229d00.flattr-badge-large.png" data-original-source="http://sametmax.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>


feed_id: http://sametmax.com/?p=7273
title: Attention chérie ça a tranché !
uri: Attention-chérie-ça-a-tranché
url: http://sametmax.com/attention-cherie-ca-a-tranche/
content:
<p>Attention chérie ça a tranché !</p>
<p>Certains d&#8217;entre vous auront remarqué que le site était down ces derniers jours, notre hébergeur a eu des petits problèmes avec ses VPS dont nous faisions partie.</p>
<p>Sam&#038;Max n&#8217;est pas mort, Sam est actuellement indisponnible jusqu&#8217;à la fin du mois et moi je suis un peu occupé en Asie, non pas que j&#8217;ai pas le temps d&#8217;écrire un article, mais pas l&#8217;envie car la tête ailleurs, j&#8217;espère que vous le comprendrez ;)</p>
<p>Pour ceux que ça interresse j&#8217;essaierai de vous faire un topo sur mon déménagement d&#8217;ici quelques semaines quand je serai revenu à une vitesse de croisière ^^</p>
<p>Bises à tous et bonnes vacances, oui nous on les prend en septembre :p</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=7273&amp;md5=f55f2dda93069ea2f79b7c9281af0d42" title="Flattr" target="_blank"><img src="media/fc229d00.flattr-badge-large.png" data-original-source="http://sametmax.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>


feed_id: http://sametmax.com/?p=7290
title: C&#8217;est l&#8217;histoire d&#8217;un blog qui traverse la route et PAF le blog
uri: C-est-l-histoire-d-un-blog-qui-traverse-la-route-et-PAF-le-blog
url: http://sametmax.com/cest-dun-blog-qui-traverse-la-route-et-paf-le-blog/
content:
<p>Retour à la normale, avec notre bon vieux WP pourri, un cache trop agressif devant, un design moche et des articles honteux.</p>
<p>Bienvenue sur Sam et Max.</p>
<p>Donc après que Lease Web nous ait lâché plusieurs fois dans le mois, notre Varnish a décidé de ne pas fonctionner pour une raison qui restera mystérieuse. Du coup on a pris un autre hébergeur, et Max, dans une tentative désespérée avant la migration, a tenté une cure par imposition des mains.</p>
<p>Ça a marché, du coup j&#8217;ai pris un serveur pour rien ^^ On va rester sur ce serveur du fait de notre flemme légendaire et parce que, bah, on a aucun revenu attaché au blog donc si il est pas disponible ça nous coûte rien à part de répondre aux tweets attristés des fans.</p>
<p>Bref, je reviens avec plein d&#8217;idées d&#8217;articles, des concepts novateurs (qui ne verront jamais le jour par manque de temps, mais c&#8217;est l&#8217;intention qui fait le forgeron) et quelques millions d&#8217;entrées dans les mails, flux RSS et autres outils dit &#8220;d&#8217;information&#8221; qui ont pour mission de s&#8217;assurer que vous n&#8217;aurez jamais la bonne, noyée dans la masse.</p>
<p>Notre référencement s&#8217;est évidement fait plomber, car un bonheur n&#8217;arrive jamais seul. Mais on s&#8217;en fout parce qu&#8217;on a encore pu profiter de la plage et du soleil pendant que vous êtes tous sous la grisaille. Et savoir que la situation des autres est pire que la sienne, ça n&#8217;a pas de prix.</p>
<p>C&#8217;est reparti !</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=7290&amp;md5=120702a769f7e77a2d3aa2e072a1a96f" title="Flattr" target="_blank"><img src="media/fc229d00.flattr-badge-large.png" data-original-source="http://sametmax.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>


feed_id: http://sametmax.com/?p=7251
title: Télécharger les vidéos de Youtube
uri: Télécharger-les-vidéos-de-Youtube
url: http://sametmax.com/telecharger-les-videos-de-youtube/
content:
<blockquote><p>
Ceci est un post invité de <a href="http://recher.wordpress.com/">Recher</a> posté sous licence <a href="http://creativecommons.org/licenses/by/3.0/">creative common 3.0 unported</a>.
</p></blockquote>
<p> &#8211; Assistance informatique, bonjour.</p>
<p> &#8211; Salut les moines bouddhistes. Comment je fais pour aller sur Youtube ? Votre stupide filtre à puceaux me bloque l&#8217;accès ! </p>
<p> &#8211; C&#8217;est lié à la politique de l&#8217;entreprise. Le site est totalement interdit.</p>
<p> &#8211; Mais bordel, c&#8217;est la pause de midi ! Je suis toute seule dans mon service, et je suis excitée ! Pas un seul stagiaire à me mettre sous la dent ! J&#8217;ai besoin de mes vidéos pornos ! Et quand je dis &#8220;besoin&#8221;, c&#8217;est VRAIMENT besoin !</p>
<p> &#8211; Veuillez m&#8217;excuser Madame, mais je ne peux rien pour vous. </p>
<p> &#8211; J&#8217;ai la patcholle qui palpite à la vitesse d&#8217;une levrette au galop ! C&#8217;est urgent !</p>
<p> &#8211; La patcholle ? Mais enfin Madame, ce mot n&#8217;existe même pas !</p>
<p> &#8211; Le mot n&#8217;existe peut-être pas, mais ma patcholle, elle, elle existe ! Et elle est pas loin de la combustion spontanée ! </p>
<p> &#8211; La seule solution serait que vous achetiez des DVD, et que vous les rameniez à votre bureau. On ne contrôle que ce que vous faites sur internet, pas ce que vous visionnez en local.</p>
<p> &#8211; Merci pour le conseil, mon p&#8217;tit chou, j&#8217;ai tout ce qu&#8217;il faut à la maison. Mais là, c&#8217;est d&#8217;une vidéo spécifique dont j&#8217;ai envie. Celle avec le nain et les ballons de baudruche. Et elle n&#8217;est que sur Youtube !</p>
<p> &#8211; Vous pouvez la télécharger. Changez l&#8217;URL, ajoutez les lettres &#8220;ss&#8221; devant le mot &#8220;youtube&#8221;, sélectionnez ensuite la qualité parmi celles disponibles, et vous récupérerez le fichier sur votre disque. Par exemple : <a href="http://www.ssyoutube.com/watch?v=uSGnmCTkIfE">http://www.ssyoutube.com/watch?v=uSGnmCTkIfE</a>. Avec un peu de chance, l&#8217;accès par la connexion de l&#8217;entreprise n&#8217;est même pas bloqué. </p>
<p> &#8211; Attendez j&#8217;essaye. Je connais l&#8217;adresse de ma vidéo par cœur. &#8230; Oh putain, ça marche ! Et ça passe même le filtre à puceaux de Youtube ! Ooouiiiii !! Va y avoir de la cyprine plein les murs !</p>
<p> &#8211; Cela m&#8217;a fait plaisir d&#8217;avoir pu vous aider, Madame.</p>
<p> &#8211; De même. Dites, pendant que ça télécharge, vous voulez pas venir me rendre visite ? On se trouverait bien quelques corpuscules de Krause avec lesquels s&#8217;occuper. </p>
<p> &#8211; Merci Madame, mais ça ne m&#8217;intéresse pas.</p>
<p> &#8211; Je vous propose du sexe gratuit et vous n&#8217;en voulez pas ? Ah d&#8217;accord, vous êtes homosexuel. J&#8217;aurais dû m&#8217;en douter, à votre petite voix fluette. De toutes façons, ils sont tous pédés dans l&#8217;informatique.</p>
<p> &#8211; Au contraire Madame, je suis hétérosexuelle. En revanche, je suis une femme. Bon après-midi à vous.</p>
<p><a href="media/a130d920.sofia-rose-07.jpg" data-original-source="http://sametmax.com/wp-content/uploads/2013/09/sofia-rose-07.jpg"><img src="media/a130d920.sofia-rose-07.jpg" data-original-source="http://sametmax.com/wp-content/uploads/2013/09/sofia-rose-07.jpg" alt="Sofia the Rose en secrétaire sexy" title="Sofia the Rose en secrétaire sexy" width="400" height="600" class="alignnone size-full wp-image-7253" /></a> </p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=7251&amp;md5=20945b0d8d47817be5eba9ebf13498d4" title="Flattr" target="_blank"><img src="media/fc229d00.flattr-badge-large.png" data-original-source="http://sametmax.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>


feed_id: http://sametmax.com/?p=7281
title: Mon premier projet Python3
uri: Mon-premier-projet-Python3
url: http://sametmax.com/mon-premier-projet-python3/
content:
<blockquote><p>
Ceci est un post invité de <a href="http://sametmax.com/author/coyote/">Coyote</a> posté sous licence <a href="http://creativecommons.org/licenses/by/3.0/">creative common 3.0 unported</a>.
</p></blockquote>
<p>Et oui, il fallait bien que ça arrive.</p>
<h3>La genèse</h3>
<p>Bon, ça avait commencé doucement. Il y a de ça quelques temps (avant même l&#8217;article de Sam), j&#8217;avais configuré mon Sublimissime pour qu&#8217;il me force les <code>import</code> du <code>__futur__</code>.<br />
Étant moi-même un peu un nazi de la convention de code, ça ne m&#8217;a pas dérangé plus que cela: les keyword <code>print</code> et autres sont pas trop ma tasse de thé. Par contre, c&#8217;est vrai que ça m&#8217;a un peu forcé la main sur les import relatifs, que j&#8217;utilisais visiblement un peu trop.</p>
<p>Récemment, sur un autre projet, je me dis “allez, je passe à la syntaxe <code>"hello {}".format("world")</code> au lieu des <code>"hello" % "world"</code>” puisque c&#8217;est ce qui est désormais recommandé. Bon, c&#8217;est un peu chiant au début mais on s&#8217;y fait vite.</p>
<p>Aussi, j&#8217;ai adopté la suppression des prefix <strong>u</strong> devant les strings. Je sais qu&#8217;avec Python 3.3 on peut à nouveau les utiliser, mais vraiment, j&#8217;ai toujours trouvé ça moche et insupportable, alors je suis <strong>très</strong> content de ne plus avoir à me les farcir.<br />
Que ceux que je vois râler me disent comment ils justifient qu&#8217;avec ce temple de la simplicité et de la lisibilité qu&#8217;est Python, on doivent préfixer toutes nos chaines par des petits <code>u</code> ridicules.</p>
<p>Voilà pour l&#8217;historique, lentement mais surement, je me préparais à prendre peut-être de bonnes habitudes pour le jour (très) lointain ou Python3 deviendrait réalité.</p>
<p>Et c&#8217;est là que mon collègue, un pervers à lunettes, nous propose d&#8217;utiliser PY3 pour de vrai, sur un nouveau projet.</p>
<p>C&#8217;est vrai que le projet s&#8217;y prêtait bien: un petit site web de CRUD avec Django. On s&#8217;est gratté le menton deux minutes et puis on s&#8217;est dit “pourquoi pas ?”.</p>
<h3>Par où commencer ?</h3>
<p>C&#8217;est con hein, mais la première chose que tu fais, c&#8217;est te demander qu&#8217;est ce qui change entre PY2 et PY3.<br />
Et bien la réponse est pas simple du tout et si tu crois que tu vas trouver une URL avec une liste de chose à changer, tu te trompes lourdement.</p>
<p>Le problème est que PY3.0 avait sans doute dû être fini à la pisse et que donc les choses ont beaucoup évoluées entre 3.0, 3.1, 3.2 et 3.3. J&#8217;ai lu beaucoup de posts sans importance sur toutes ces étapes intermédiaires, mais la conclusion, c&#8217;est que grosso-modo, il faut passer de 2.7 à 3.3. Entre les deux, c&#8217;est un peu comme naitre au <a href="https://fr.wikipedia.org/wiki/Sahara_Occidental">Sahara Occidental</a>.</p>
<h3>Installer PY3.3</h3>
<p>Comme on travaille en équipe, on a des setup différents: OSX, Ubuntu 12.04 et Ubuntu 13.04.</p>
<p>Ça c&#8217;est passé sans douleur malgré les appréhensions. Pour Ubuntu, il suffit d&#8217;utiliser le <a href="https://launchpad.net/~fkrull/+archive/deadsnakes">ppa deadsnakes</a>.<br />
Une fois installé, un coup de <em>virtualenv</em> (<code>mkvirtualenv -p /usr/bin/python3.3 monenv3</code>) et c&#8217;est parti.</p>
<h3>Les dépendances</h3>
<p>Comme expliqué plus haut, on a choisi de faire ce projet en PY3 parce qu&#8217;il est petit et sans dépendances ; donc pas très représentatif.<br />
Cependant, on utilise:<br />
<code>Django==1.5.4<br />
South==0.8.2<br />
django-mptt==0.6.0<br />
django-picklefield==0.3.0<br />
numpy==1.7.1<br />
unicodecsv*</code></p>
<p>Aucun problème avec ceux là. On a cru que South nous faisait des misères mais en fait c&#8217;était un import relatif avec un <code>pass</code> de cochon qui foutait la merde (<code>try: from local_settings import * except ImportError: pass</code>.<br />
Donc la leçon ici, c&#8217;est que <strong>les imports relatifs c&#8217;est mal</strong>.</p>
<p>Au niveau des dépendances, on a du se séparer de batbelt. Oui, je parle bien de <a href="https://github.com/sametmax/Bat-belt">sametmax/Bat-Belt</a> qui n&#8217;est pas du tout PY3 proof. Ne pleurez pas, moi aussi j&#8217;ai été très déçu et j&#8217;attends des explications (foireuses, je les vois venir d&#8217;ici).</p>
<p>Bref, comme on utilise batbelt pour presque rien, on a copié honteusement (<a href="https://en.wikipedia.org/wiki/Zlib_License">ou pas</a>) le code nécessaire.</p>
<p>Dernière remarque, vous voyez dans la liste <code>unicodecsv</code>. C&#8217;est un peu tricky puisque PY3 supporte unicode par défaut, le module <code>csv</code> de PY3 fonctionne directement ; et de fait, <code>unicodecsv</code> n&#8217;existe plus. Oui, je me suis fait avoir comme un débutant.<br />
Bref, comme on souhaite aussi supporter PY2 et pas uniquement PY3, on a un beau <code>if PY2: import unicodecsv as csv else: import csv</code>.</p>
<h3>Les problèmes</h3>
<p>Peu nombreux je dois dire et c&#8217;est plutôt encourageant. De tête:</p>
<ul>
<li>Fini les <code>__unicode__()</code> dans les modèles Django.<br />
Pour gérer ce cas à la con, on utilise ce <a href="https://raw.github.com/mitsuhiko/jinja2/master/jinja2/_compat.py">fichier _compat de Jinja2</a>. Je vous encourage à le copier, il défini notamment la variable PY2 pratique pour switcher comme le cas du csv ci-dessus.<br />
Bref, dans ce _compat, il y a un class decorator <code>implements_to_string</code> qui permet de ne définir que <code>__str__()</code> (renvoie de l&#8217;unicode) et le reste est géré automatiquement.<br />Django propose la même chose via <code>django.utils.encoding.python_2_unicode_compatible</code> mais je préfère la toolbox Jinja.</li>
<li>J&#8217;ai parlé dans les dépendances du cas <code>unicodecsv</code>. Ici c&#8217;était le seul, mais clairement dans beaucoup de projet qui manipulent des stream ou des fichiers, il va falloir faire ce genre de combines pour suporter PY2 et PY3.</li>
<li>Un edge case très rigolo (après coup!) avec le <code>django-picklefield</code>. Le field se comportait correctement avec PY3 mais pas avec PY2 et pas dans tous les cas. Du bonheur à <s>tariner</s>déboguer.<br />Pour l&#8217;anecdote: <code><br />
x = MyModel(id=1)<br />
x.picklefield = [1,2,3]<br />
x.save()</p>
<p>x = MyModel(id=2)<br />
x.picklefield = {'a': 1, 'b': 3}<br />
x.save()</code><br />
Ce code fonctionne bien avec PY3, mais avec PY2, le fait de réutiliser le même nom de variable rend le PickleField tout chose et donc il sérialise deux fois la valeur passée. Encore une fois, <strong>la leçon ici est d&#8217;être rigoureux</strong>.</li>
<li>Les fonctions du type <code>dict.keys()</code> et assimilés ne renvoient plus de listes, mais ont été remplacés par leur équivalents générateurs (<code>dict.iterkeys()</code>) et ceux-ci n&#8217;existent plus. Donc un peu de gymnastique syntaxique quand on est habitué à l&#8217;ancienne syntaxe.</li>
<li>Numpy refusait de s&#8217;installer sur certaines versions d&#8217;Ubuntu (je me souviens plus laquelle) car il ne trouvait pas un des headers de Python. C&#8217;est du au fait qu&#8217;il cherche ce header dans le même répertoire que le header précédent alors qu&#8217;il est stocké ailleurs. Un symlink fait l&#8217;affaire.</li>
<li>Enfin, le dernier problème, qui va réveler que <strong>tout ceci n&#8217;est qu&#8217;une imposture</strong>: <code>chaussette</code> et <code>circus</code> que j&#8217;utilise pour le déploiement ne sont pas compatibles PY3 !! Pas de debug ici, ça ne s&#8217;installe même pas. Résulalt: <strong>on a déployé en PY 2.7</strong>. Bon, pour vous consoler (et moi avec), le github de ces 2 projets est plein de commits récents en rapport avec PY3 donc j&#8217;imagine que ça ne saurait tarder.</li>
</ul>
<h3>Conclusion</h3>
<p>Et bien, on a un petit projet développé à plusieurs, en PY3.3, qui est déployé en PY2.7 donc c&#8217;est possible ; on a pas rencontré de grande difficultées donc je pense que pour du web, c&#8217;est pas loin d&#8217;être mûr.</p>
<p><strong>Pas grand chose à dire</strong> finalement, et c&#8217;est sans doute ça le plus important !</p>
<p>Allez bookmarker le site <a href="http://python3porting.com">python3porting</a> qui contient les infos sur ce qui a changé. Ca a l&#8217;air long mais en fait, y&#8217;a beaucoup de cas spécifiques.</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=7281&amp;md5=dec3880c1a22a4a73680bebe3f8f04fc" title="Flattr" target="_blank"><img src="media/fc229d00.flattr-badge-large.png" data-original-source="http://sametmax.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>


feed_id: http://sametmax.com/?p=7320
title: La magie des booléens en Python
uri: La-magie-des-booléens-en-Python
url: http://sametmax.com/la-magie-des-booleens-en-python/
content:
<p>Dans un langage fortement typé comme Python, on ne peut pas additionner des choux et des carottes, comme disait madame Germaine, ma prof de mate.</p>
<div id="attachment_7321" class="wp-caption aligncenter" style="width: 387px"><a href="media/54c2d9a0.1248528858645.jpg" data-original-source="http://sametmax.com/wp-content/uploads/2013/10/1248528858645.jpg"><img src="media/54c2d9a0.1248528858645.jpg" data-original-source="http://sametmax.com/wp-content/uploads/2013/10/1248528858645.jpg" alt="Photo d&#039;une pinup déguisée en prof" title="J&#039;ai toujours eu des soucis d&#039;intégration en cours de maths. Mon attention était discontinue et je ne me sentais pas dans mon domaine." width="377" height="512" class="size-full wp-image-7321" /></a><p class="wp-caption-text">J&#039;ai toujours eu des soucis d&#039;intégration en cours de maths. Mon attention était discontinue et je ne me sentais pas dans mon domaine.</p></div>
<p>Par exemple on ne peut pas faire ça :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #ff4500;">1</span> + <span style="color: #483d8b;">&quot;1&quot;</span>
Traceback <span style="color: black;">&#40;</span>most recent call last<span style="color: black;">&#41;</span>:
  File <span style="color: #483d8b;">&quot;&lt;stdin&gt;&quot;</span>, line <span style="color: #ff4500;">1</span>, <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #66cc66;">&lt;</span>module<span style="color: #66cc66;">&gt;</span>
<span style="color: #008000;">TypeError</span>: unsupported operand <span style="color: #008000;">type</span><span style="color: black;">&#40;</span>s<span style="color: black;">&#41;</span> <span style="color: #ff7700;font-weight:bold;">for</span> +: <span style="color: #483d8b;">'int'</span> <span style="color: #ff7700;font-weight:bold;">and</span> <span style="color: #483d8b;">'str'</span></pre></div></div>

<p>Nonnnnnnnn !</p>
<p>Ni ça :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: black;">&#91;</span><span style="color: #ff4500;">1</span><span style="color: black;">&#93;</span> + <span style="color: black;">&#40;</span><span style="color: #ff4500;">1</span>,<span style="color: black;">&#41;</span>
Traceback <span style="color: black;">&#40;</span>most recent call last<span style="color: black;">&#41;</span>:
  File <span style="color: #483d8b;">&quot;&lt;stdin&gt;&quot;</span>, line <span style="color: #ff4500;">1</span>, <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #66cc66;">&lt;</span>module<span style="color: #66cc66;">&gt;</span>
<span style="color: #008000;">TypeError</span>: can only concatenate <span style="color: #008000;">list</span> <span style="color: black;">&#40;</span><span style="color: #ff7700;font-weight:bold;">not</span> <span style="color: #483d8b;">&quot;tuple&quot;</span><span style="color: black;">&#41;</span> to <span style="color: #008000;">list</span></pre></div></div>

<p>Pas biennnnnnnnnnnnnn !</p>
<p>Et pas ça :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #008000;">True</span> + <span style="color: #ff4500;">1</span>
<span style="color: #ff4500;">2</span></pre></div></div>

<p>OUATE ZE PHOQUE ?</p>
<h2>Les booléens sont des entiers déguisés</h2>
<p>Pendant longtemps, Python n&#8217;a pas eu de type bool, et on utilisait, comme en C, 0 pour faux, et 1 pour vrai. Ça marchait pas mal, mais dans un souci de rentre le langage plus propre, on a voulu créer une type spécialisé, et ainsi :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #008000;">type</span><span style="color: black;">&#40;</span><span style="color: #008000;">True</span><span style="color: black;">&#41;</span>
<span style="color: #66cc66;">&lt;</span>class <span style="color: #483d8b;">'bool'</span><span style="color: #66cc66;">&gt;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #008000;">type</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span>
<span style="color: #66cc66;">&lt;</span>class <span style="color: #483d8b;">'int'</span><span style="color: #66cc66;">&gt;</span></pre></div></div>

<p>Mais il faut avouer que pouvoir interchanger True pour 1 et False pour 0 et vice versouille, c&#8217;était achement pratique dans une discipline ou la manipulation des chiffres à des fins logiques est un peu la base du métier. Du coup il a été décidé que les booléen seraient des travs, juste une surcouche au dessus des entiers, et qu&#8217;on pourrait les utiliser en lieu et place de ceux-ci. Une exception étonnante vu la rigueur du langage sur la gestion des types. </p>
<p>Du coup :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #008000;">True</span> == <span style="color: #ff4500;">1</span>
<span style="color: #008000;">True</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #008000;">False</span> == <span style="color: #ff4500;">0</span>
<span style="color: #008000;">True</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #008000;">True</span> + <span style="color: #ff4500;">1</span>
<span style="color: #ff4500;">2</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #008000;">False</span> - <span style="color: #ff4500;">1</span>
-<span style="color: #ff4500;">1</span></pre></div></div>

<p>Par contre :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #ff4500;">1</span> <span style="color: #ff7700;font-weight:bold;">is</span> <span style="color: #ff4500;">1</span>
<span style="color: #008000;">True</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #008000;">True</span> <span style="color: #ff7700;font-weight:bold;">is</span> <span style="color: #008000;">True</span>
<span style="color: #008000;">True</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #008000;">True</span> <span style="color: #ff7700;font-weight:bold;">is</span> <span style="color: #ff4500;">1</span>
<span style="color: #008000;">False</span></pre></div></div>

<h2>Et qui dit exception, dit hack</h2>
<p>Donc voici quelques moyens de détourner l&#8217;utilisation des booléens pour écrire du Perlthon&#8230;</p>
<p>On peut utiliser un bool pour de l&#8217;indexing ou du slicing :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: black;">&#40;</span><span style="color: #483d8b;">'Valeur 1'</span>, <span style="color: #483d8b;">'Valeur 2'</span><span style="color: black;">&#41;</span><span style="color: black;">&#91;</span><span style="color: #008000;">True</span><span style="color: black;">&#93;</span>
<span style="color: #483d8b;">'Valeur 2'</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #008000;">list</span><span style="color: black;">&#40;</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><span style="color: black;">&#91;</span><span style="color: #008000;">True</span>:False-<span style="color: #ff4500;">1</span>:<span style="color: #ff4500;">2</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span>
<span style="color: black;">&#91;</span><span style="color: #ff4500;">1</span>, <span style="color: #ff4500;">3</span>, <span style="color: #ff4500;">5</span>, <span style="color: #ff4500;">7</span><span style="color: black;">&#93;</span></pre></div></div>

<p>On peut utiliser un bool pour multiplier, et l&#8217;opération multiplier marche sur les strings et les listes&#8230;</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #483d8b;">&quot;J'aime les chat&quot;</span> + <span style="color: #483d8b;">&quot;s&quot;</span> <span style="color: #66cc66;">*</span> est_pluriel
<span style="color: #483d8b;">&quot;J'aime les chat&quot;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> est_pluriel = <span style="color: #008000;">True</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #483d8b;">&quot;J'aime les chat&quot;</span> + <span style="color: #483d8b;">&quot;s&quot;</span> <span style="color: #66cc66;">*</span> est_pluriel
<span style="color: #483d8b;">&quot;J'aime les chats&quot;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #ff7700;font-weight:bold;">def</span> process<span style="color: black;">&#40;</span>lst, cancel=<span style="color: #008000;">False</span><span style="color: black;">&#41;</span>:
...     <span style="color: black;">lst</span> = <span style="color: #008000;">list</span><span style="color: black;">&#40;</span>lst<span style="color: black;">&#41;</span> <span style="color: #66cc66;">*</span> <span style="color: black;">&#40;</span><span style="color: #ff7700;font-weight:bold;">not</span> cancel<span style="color: black;">&#41;</span>
...     <span style="color: #ff7700;font-weight:bold;">for</span> i <span style="color: #ff7700;font-weight:bold;">in</span> lst:
...         <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span>i<span style="color: black;">&#41;</span>
... 
<span style="color: #66cc66;">&gt;&gt;&gt;</span> process<span style="color: black;">&#40;</span><span style="color: #008000;">range</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">3</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
<span style="color: #ff4500;">0</span>
<span style="color: #ff4500;">1</span>
<span style="color: #ff4500;">2</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> process<span style="color: black;">&#40;</span><span style="color: #008000;">range</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">3</span><span style="color: black;">&#41;</span>, <span style="color: #008000;">True</span><span style="color: black;">&#41;</span></pre></div></div>

<p>Ou même pire, saviez-vous que la déclaration d&#8217;héritage et les clauses d&#8217;exception pouvaient inclure une expression ? En rajoutant de l&#8217;unpacking, on obtient un truc bien marrant :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #ff7700;font-weight:bold;">class</span> Parent:
...     <span style="color: black;">foo</span> = <span style="color: #483d8b;">&quot;bar&quot;</span>
... 
<span style="color: #66cc66;">&gt;&gt;&gt;</span> inherit = <span style="color: #008000;">False</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #ff7700;font-weight:bold;">class</span> Enfant<span style="color: black;">&#40;</span><span style="color: #66cc66;">*</span><span style="color: black;">&#91;</span>Parent<span style="color: black;">&#93;</span> <span style="color: #66cc66;">*</span> inherit<span style="color: black;">&#41;</span>:
...     <span style="color: #ff7700;font-weight:bold;">pass</span>
... 
<span style="color: #66cc66;">&gt;&gt;&gt;</span> Enfant<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>.<span style="color: black;">foo</span>
Traceback <span style="color: black;">&#40;</span>most recent call last<span style="color: black;">&#41;</span>:
  File <span style="color: #483d8b;">&quot;&lt;stdin&gt;&quot;</span>, line <span style="color: #ff4500;">1</span>, <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #66cc66;">&lt;</span>module<span style="color: #66cc66;">&gt;</span>
<span style="color: #008000;">AttributeError</span>: <span style="color: #483d8b;">'Enfant'</span> <span style="color: #008000;">object</span> has no attribute <span style="color: #483d8b;">'foo'</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> inherit = <span style="color: #008000;">True</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #ff7700;font-weight:bold;">class</span> Enfant<span style="color: black;">&#40;</span><span style="color: #66cc66;">*</span><span style="color: black;">&#91;</span>Parent<span style="color: black;">&#93;</span> <span style="color: #66cc66;">*</span> inherit<span style="color: black;">&#41;</span>:
...     <span style="color: #ff7700;font-weight:bold;">pass</span>
... 
<span style="color: #66cc66;">&gt;&gt;&gt;</span> Enfant<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>.<span style="color: black;">foo</span>
<span style="color: #483d8b;">'bar'</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> catch = <span style="color: #008000;">True</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #ff7700;font-weight:bold;">try</span>:
...     <span style="color: #ff4500;">42</span> / <span style="color: #ff4500;">0</span>
... <span style="color: #ff7700;font-weight:bold;">except</span> <span style="color: black;">&#40;</span><span style="color: #008000;">ZeroDivisionError</span>,<span style="color: black;">&#41;</span> <span style="color: #66cc66;">*</span> catch:
...     <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;Nope&quot;</span><span style="color: black;">&#41;</span>
Nope
<span style="color: #66cc66;">&gt;&gt;&gt;</span> catch = <span style="color: #008000;">False</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #ff7700;font-weight:bold;">try</span>:
...     <span style="color: #ff4500;">42</span> / <span style="color: #ff4500;">0</span>
... <span style="color: #ff7700;font-weight:bold;">except</span> <span style="color: black;">&#40;</span><span style="color: #008000;">ZeroDivisionError</span>,<span style="color: black;">&#41;</span> <span style="color: #66cc66;">*</span> catch:
...     <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;Nope&quot;</span><span style="color: black;">&#41;</span>
Traceback <span style="color: black;">&#40;</span>most recent call last<span style="color: black;">&#41;</span>:
  File <span style="color: #483d8b;">&quot;&lt;ipython-input-12-c01f7e27284d&gt;&quot;</span>, line <span style="color: #ff4500;">2</span>, <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #66cc66;">&lt;</span>module<span style="color: #66cc66;">&gt;</span>
    <span style="color: #ff4500;">42</span> / <span style="color: #ff4500;">0</span>
<span style="color: #008000;">ZeroDivisionError</span>: division by zero</pre></div></div>

<p>Évidelement ça marche avec n&#8217;importe quels entiers, mais où serait le fun ?</p>
<p>Et on peut utiliser un bool pour incrémenter une valeur.</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">&gt;&gt;&gt;</span> increment = <span style="color: #008000;">True</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> value = <span style="color: #ff4500;">0</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;">range</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">10</span><span style="color: black;">&#41;</span>:
...     <span style="color: black;">value</span> += increment
... 
<span style="color: #66cc66;">&gt;&gt;&gt;</span> value
<span style="color: #ff4500;">10</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> increment = <span style="color: #008000;">False</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;">range</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">10</span><span style="color: black;">&#41;</span>:
...     <span style="color: black;">value</span> += increment
... 
<span style="color: #66cc66;">&gt;&gt;&gt;</span> value
<span style="color: #ff4500;">10</span></pre></div></div>

<p>Voilà de quoi bien vous marrer au boulot lors de votre prochaine code review !</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=7320&amp;md5=25e9a85c7999cc4aed4e148257f0966f" title="Flattr" target="_blank"><img src="media/fc229d00.flattr-badge-large.png" data-original-source="http://sametmax.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>


feed_id: http://sametmax.com/?p=7326
title: Django, une app à la fois : les fichiers statiques
uri: Django-une-app-à-la-fois-les-fichiers-statiques
url: http://sametmax.com/django-un-app-a-la-fois-les-fichiers-statiques/
content:
<p>On continue avec les <a href="http://sametmax.com/django-une-app-a-la-fois/">applications Django qui démontrent un aspect du framework, avec des sources blindées de commentaires</a>.</p>
<p>Cette fois, c&#8217;est la gestion des fichiers statiques. <a href="https://github.com/sametmax/Django--an-app-at-a-time/tree/fran%C3%A7ais">Chopez le code</a> quand il est encore chaud !</p>
<p>@+</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=7326&amp;md5=6c2fd2ed9a322d44f0ff5bdd5bbd439e" title="Flattr" target="_blank"><img src="media/fc229d00.flattr-badge-large.png" data-original-source="http://sametmax.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>


feed_id: http://sametmax.com/?p=7331
title: Chers vendeurs de livres électroniques
uri: Chers-vendeurs-de-livres-électroniques
url: http://sametmax.com/chers-vendeurs-de-livres-electroniques/
content:
<p>Il n&#8217;y a rien de plus facile à pirater qu&#8217;un livre. Ils ne sont pas surveillés, les DRM se cassent facilement et ils sont de taille très réduite, rendant le téléchargement aisé. Sans compter que le texte est une donnée simple d&#8217;accès.</p>
<p>Sachant cela, ne croyez-vous pas qu&#8217;il faille travailler un peu votre produit afin de le rendre attractif afin d&#8217;inciter les personnes à payer plutôt que de pirater ?</p>
<p>Et donc de répondre à ces questions :</p>
<ul>
<li>Pourquoi un version électronique coûte PLUS cher qu&#8217;une version papier ?</li>
<li>Pourquoi un livre qui a demandé le travail de 10 / 20 personnes est 10 fois plus cher qu&#8217;un jeu smartphone qui a demandé le travail de 50 personnes sur les app stores ? L&#8217;effet d&#8217;échelle n&#8217;excuse rien dès qu&#8217;on tape dans des best sellers.</li>
<li>Pourquoi traitez-vous la version numérique comme un produit secondaire à laquelle on n&#8217;apporte aucune attention (copier / coller merdique, formats de fichiers limités, pas de liens hypertextes, mise en page à l&#8217;arrache, etc) ?</li>
</ul>
<p>N&#8217;avez-vous pas appris de la stupidité de l&#8217;industrie musicale et vidéo qui ont fait les mêmes erreurs 10 ans avant vous ?</p>
<p>Sortez-vous les doigts du cul.</p>
<p>Signé : un lecteur qui vous a déjà beaucoup rapporté de pognon et qui est prêt à payer plus.</p>
<hr />
<p>Sinon, je viens d&#8217;acheter une <a href="http://www.kobo.com/koboaurahd">Kobo Aura</a> et je suis en train de revenir sur mon nazisme &#8216;tout-format-papier&#8217;. C&#8217;est vrai que c&#8217;est pas mal ce truc.</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=7331&amp;md5=ad7ecb2fcffe295ff156574aaa0ae604" title="Flattr" target="_blank"><img src="media/fc229d00.flattr-badge-large.png" data-original-source="http://sametmax.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>


feed_id: http://sametmax.com/?p=7346
title: Nouveauté de Django 1.6 : ENFINNNNNNNNNNNNN !
uri: Nouveauté-de-Django-1-6-ENFINNNNNNNNNNNNN
url: http://sametmax.com/nouveaute-de-django-1-6-enfinnnnnnnnnnnnn/
content:
<p><a href="https://docs.djangoproject.com/en/dev/releases/1.6/">Django 1.6 est sur les rails</a>, et il y a des changements que j&#8217;attends depuis 3 éternités dedans.</p>
<h2>Support officiel de Python 3</h2>
<p>Là, on pourra dire que Python 3 est crédible. Là, on peut commencer à faire du Python 3.</p>
<p>Après il restera toujours Python 2 par défaut sur certains OS, donc il y a encore du chemin. Je vous rappelle qu&#8217;Ubuntu avait prévu de migrer il y a 2 ans. LOL.</p>
<h2>Template de projet simplifié</h2>
<p>Enfin, un nouveau projet commence avec l&#8217;admin activée par défaut.</p>
<p>Enfin, la base de données est configurée par défaut pour utiliser SQLite. Ca qui signifie que Django marche VRAIMENT out of the box. Un débutant à juste à commencer à coder.</p>
<p>C&#8217;était le dernier gros bloc à mon sens pour permettre à quelqu&#8217;un de se lancer sans avoir à chercher à comprendre comment tout marche.</p>
<h2>Des réglages de DB moins cons</h2>
<p>Les transactions en Django, c&#8217;était cryptique. Maintenant c&#8217;est tout simplement de l&#8217;autocommit par défaut (configurable). Et si on veut avoir plein de queries dans une seule transaction :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">    <span style="color: #ff7700;font-weight:bold;">with</span> transaction.<span style="color: black;">atomic</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
        query1<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
        query2<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span></pre></div></div>

<p>Putain, enfin !</p>
<p>Et en prime, on peut avoir une connexion persistante à la base de données et éviter des setups à base de psycopg2_pool. Je vais jouir.</p>
<p>Au passage, si vous lisez <a href="https://docs.djangoproject.com/en/dev/ref/databases/#persistent-database-connections">la doc sur les DB</a>, c&#8217;est plus ou moins un appel à migrer de MySQL à PostGres si vous le pouvez. Maintenant il n&#8217;y a plus que des avantages.</p>
<p>Autre goodies : <code>save()</code> fait maintenant une query au lieu de deux dans le cas d&#8217;un update. Alléluia mes frères !</p>
<p>Pour finir, on a un field pour stocker des données binaires brut en DB. Et la valeur de <code>BooleanField</code> est <code>None</code> (<code>NULL</code> en DB) par défaut, et plus <code>False</code>. Pas trop tôt&#8230;</p>
<h2>Quelques bonbons</h2>
<p>Ceux qui écrivent des backend d&#8217;authentification seront heureux d&#8217;apprendre que l&#8217;on pourra lever <code>PermissionDenied</code> à tout instant pour se simplifier la vie.</p>
<p>Les amateurs de <code>latest()</code> n&#8217;auront plus à faire un <code>sort()</code> avant pour obtenir le premier élément, il suffit de faire <code>earliest()</code>. Et on n&#8217;aura plus à faire un <code>try/except</code> sur un <code>filter()[0]</code> pour obtenir le premier élément, <code>first()</code> permet de le faire (et <code>last()</code> pour le dernier) et retournera <code>None</code> si ça foire..</p>
<p>Certains fields de formulaire passent en HTLM5, par exemple <code>EmailField</code> output <code>type="email"</code>. Ah, les labels de forms contiennent maintenant une option <code>suffix</code>, qui a pour défaut &#8220;<code>:</code>&#8220;.</p>
<p>Les <code>ModelForm</code> peuvent écraser le message d&#8217;erreur d&#8217;un champ, sans avoir à réécrire le champ. Des dizaines de lignes qui vont sauter, yes ! De plus il n&#8217;ont plus la grosse faille de sécurité qui supposait que tous les champs du modèle (y compris l&#8217;ID) étaient exposés si on ne précisait rien. Si vous voulez ce comportement, il faudra explicitement mettre <code>fields = "__all__"</code>.</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=7346&amp;md5=f32c265565cd3bfe6fecea2dbf7a4ab2" title="Flattr" target="_blank"><img src="media/fc229d00.flattr-badge-large.png" data-original-source="http://sametmax.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>


feed_id: http://sametmax.com/?p=7342
title: Trop de mails
uri: Trop-de-mails
url: http://sametmax.com/trop-de-mails/
content:
<p>On a reçu pas mal de mails avec des demandes d&#8217;aide, des signalements de blog down, le fait qu&#8217;on ne postait plus, etc.</p>
<p>Pour les demandes d&#8217;aide, je vais faire comme d&#8217;hab, c&#8217;est à dire rediriger vers l&#8217;AFPY.</p>
<p>Par contre pour les mails de signalement de blog down ou qui demande si on est mort car on ne postait pas trop en septembre, exceptionnellement, je vais les mettre à la poubelle. Pas par manque de respect, mais parce que je crois que les événements ont répondu à ces mails tout seul, et là on a carrément pas le temps.</p>
<p>Pour les autres, patientez, on met très longtemps à répondre. Ça peut prendre 3 mois. Littéralement, 3 mois. 3 fois 30 jours. Pour de vrai.</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=7342&amp;md5=6642efecdf97b9a30fcd1c184eaa022b" title="Flattr" target="_blank"><img src="media/fc229d00.flattr-badge-large.png" data-original-source="http://sametmax.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>


feed_id: http://sametmax.com/?p=7369
title: Max n&#8217;est pas mort
uri: Max-n-est-pas-mort
url: http://sametmax.com/max-nest-pas-mort/
content:
<p>Je sais que ça manque un peu de sa patte fine et subtile ces temps-ci, même dans les comments. Je l&#8217;ai eu sur Skype dernièrement et il va bien, simplement il profite de la vie Thaïlandaise et tous ses potes viennent lui rendre visite. </p>
<p>Bref, difficile de concurrencer l&#8217;attrait de son rythme de vie actuel avec la promesse d&#8217;un retweet :-)</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=7369&amp;md5=a8a6af3639e6437b45e58e8b1713dfb7" title="Flattr" target="_blank"><img src="media/fc229d00.flattr-badge-large.png" data-original-source="http://sametmax.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>


feed_id: http://sametmax.com/?p=7378
title: La différence entre la programmation asynchrone, parallèle et concurrente
uri: La-différence-entre-la-programmation-asynchrone-parallèle-et-concur
url: http://sametmax.com/la-difference-entre-la-programmation-asynchrone-parallele-et-concurrente/
content:
<p>On parle un peu partout de programmation non bloquante ces temps-ci. NoSQL a remis le map/reduce au goût du jour, et PAF, on vous sort le mot clé parallélisation pour vous en vendre une tetrachiée. Les partisants de NodeJS vont crier &#8220;asynchrone&#8221;, parce que c&#8217;est ce que Javascript sait faire de mieux. Et on murmure dans les coins que la robustesse d&#8217;Erlang tient dans ses acteurs qui travaillent de manière concurrente dans la VM.</p>
<p>Ok, donc tout ça, ça à l&#8217;air de faire la même chose, c&#8217;est à dire de faire plusieurs choses en même temps, sans bloquer.</p>
<p>Donc c&#8217;est pareil ?</p>
<p>Non. En fait c&#8217;est une question de point de vue : non bloquant dans quel contexte ?</p>
<h2>Si c&#8217;est l&#8217;IO, c&#8217;est asynchrone</h2>
<p>Pour rappel, l&#8217;IO (Input/Ouput), c&#8217;est toute activité qui implique que des données entrent et sortent de votre programme : saisie utilisateur, print sur un terminal, lecture sur une socket, écriture sur le disque, etc. Une opération I/O a plusieurs caractéristiques :</p>
<ul>
<li>Le temps que prend l&#8217;opération n&#8217;est pas dépendant du CPU : la vitesse du disque, la latence du réseau, le nombre d&#8217;heures de sommeil du sysadmin sont les facteurs qui vont déterminer quand l&#8217;opération va prendre fin.</li>
<li>Le corollaire, c&#8217;est qu&#8217;on ne peut pas prédire quand l&#8217;opération va prendre fin depuis le programme.</li>
<li>Sur les services avec beaucoup d&#8217;I/O (serveurs Web, bases de données, crawlers, scripts de déploiement, etc), c&#8217;est l&#8217;I/O qui généralement prend le plus de temps dans l&#8217;exécution du programme. L&#8217;optimisation de ces opérations va donc l&#8217;accélérer bien plus que de changer votre algo.</li>
</ul>
<p>La plupart des programmes bloquent quand ils effectuent une opération I/O. Par exemple, si vous faites ceci en Python :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">urllib2</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># télécharge et affiche le contenu de la page d'acceuil de sam et max</span>
<span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span><span style="color: #dc143c;">urllib2</span>.<span style="color: black;">urlopen</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'http://sametmax.com'</span><span style="color: black;">&#41;</span>.<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: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;Coucou&quot;</span><span style="color: black;">&#41;</span></pre></div></div>

<p>La ligne <code>print("Coucou")</code> ne s&#8217;exécutera pas tant que la ligne précédente n&#8217;aura pas terminé de s&#8217;exécuter. Dans ce cas ce n&#8217;est pas très grâve, mais dans ce cas là :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">urllib2</span>
&nbsp;
&nbsp;
mille_urls = obtenir_liste_de_mille_urls<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
contenu = <span style="color: black;">&#91;</span><span style="color: black;">&#93;</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># télécharge et sauvegarde dans une liste</span>
<span style="color: #808080; font-style: italic;"># le contenu de chacune des 1000 urls</span>
<span style="color: #ff7700;font-weight:bold;">for</span> url <span style="color: #ff7700;font-weight:bold;">in</span> mille_urls:
	contenu.<span style="color: black;">append</span><span style="color: black;">&#40;</span><span style="color: #dc143c;">urllib2</span>.<span style="color: black;">urlopen</span><span style="color: black;">&#40;</span>url<span style="color: black;">&#41;</span>.<span style="color: black;">read</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span></pre></div></div>

<p>Chaque url est téléchargée une par une, et comme Internet, c&#8217;est vachement lent (300 ms X 1000, ça fait 5 minutes, mine de rien), votre programme va prendre un temps fou. Et pour rien en plus, car votre programme va passer la majeure partie du temps à ne rien faire ! En effet, 99% du temps de votre programme est passé à attendre qu&#8217;Internet réponde, pendant que votre CPU se touche les noix.</p>
<p>La programmation asynchrone est une réponse à cela : au lieu d&#8217;attendre que se finissent les entrées et les sorties, le programme continue de fonctionner. </p>
<p>Une autre problématique se pose alors : comment obtenir le résultat de l&#8217;opération d&#8217;I/O, puisqu&#8217;on ne sait pas quand il va arriver et qu&#8217;on attend pas qu&#8217;il arrive ?</p>
<p>C&#8217;est là que les systèmes synchrones font un peu de magie. En vérité, une partie du programme attend, mais discrètement, en arrière plan, au niveau de ce qu&#8217;on appelle une boucle d&#8217;événements (&#8220;events loop&#8221;), c&#8217;est à dire une boucle infinie qui check régulièrement si une opération I/O ne s&#8217;est pas terminée. </p>
<p>Cette boucle est invisible pour vous, votre programme continue de tourner. Mais si une opération I/O envoie des données, alors l&#8217;events loop va réagir.</p>
<p>Ca a l&#8217;air compliqué, mais en fait, c&#8217;est, la plupart du temps, juste une histoire de callback (si la notion vous échappe, je vous renvois à <a href="http://sametmax.com/quest-ce-quun-callback/">l&#8217;article dédié</a>&#8230;). Par exemple en Javascript :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">var mille_urls = obtenir_liste_de_mille_urls<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><span style="color: #66cc66;">;</span>
var contenu = <span style="color: black;">&#91;</span><span style="color: black;">&#93;</span><span style="color: #66cc66;">;</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># notre callback qui va permettre d'ajouter </span>
<span style="color: #808080; font-style: italic;"># le contenu téléchargé à notre liste</span>
var callback = function<span style="color: black;">&#40;</span>data<span style="color: black;">&#41;</span> <span style="color: black;">&#123;</span> 
      contenu.<span style="color: black;">push</span><span style="color: black;">&#40;</span>data<span style="color: black;">&#41;</span><span style="color: #66cc66;">;</span>
<span style="color: black;">&#125;</span><span style="color: #66cc66;">;</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Bon, j'utilise jquery pour simplifier le code...</span>
<span style="color: #808080; font-style: italic;"># On boucle sur les milles URL</span>
$.<span style="color: black;">each</span><span style="color: black;">&#40;</span>mille_urls, function<span style="color: black;">&#40;</span>index, url<span style="color: black;">&#41;</span> <span style="color: black;">&#123;</span>
  <span style="color: #808080; font-style: italic;"># On télécharge le contenu, MAIS comme</span>
  <span style="color: #808080; font-style: italic;"># $.get est naturellement non blocante,</span>
  <span style="color: #808080; font-style: italic;"># elle ne va pas attendre qu'internet </span>
  <span style="color: #808080; font-style: italic;"># réponde pour continuer la boucle, et</span>
  <span style="color: #808080; font-style: italic;"># donc on pourra attendre plusieurs réponses</span>
  <span style="color: #808080; font-style: italic;"># en même temps. Pour avoir le résultat de </span>
  <span style="color: #808080; font-style: italic;"># chaque réponse, on passe un callback qui </span>
  <span style="color: #808080; font-style: italic;"># va être appelé quand la réponse arrive.</span>
  $.<span style="color: black;">get</span><span style="color: black;">&#40;</span>url, callback<span style="color: black;">&#41;</span><span style="color: #66cc66;">;</span>
&nbsp;
<span style="color: black;">&#125;</span><span style="color: black;">&#41;</span><span style="color: #66cc66;">;</span></pre></div></div>

<p>Comprenez bien la subtilité : à tout moment, il n&#8217;y a qu&#8217;UN SEUL process javascript qui s&#8217;éxécute. Il n&#8217;y a pas deux traitements, pas de threads, pas de processus parallèles, rien de tout ça. Simplement, Javascript n&#8217;attend pas la réponse de sa requête pour faire la requête suivante, il continu sur sa lancée, et donc <strong>peut optimiser les temps d&#8217;attente en attendant plusieurs choses en même temps</strong>.</p>
<p>Javascript utilise massivement des API asynchrones, c&#8217;est au cœur du langage, il n&#8217;y a aucun effort à faire pour cela. A l&#8217;inverse, Python est synchrone par nature, et il faut vraiment se faire chier pour obtenir un algo asynchrone. Ceci changera avec Python 3.4 qui accueillera <a href="https://code.google.com/p/tulip/">tulip</a> dans la stdlib, afin de se moderniser sur ce point. En attendant, si vous voulez faire de l&#8217;asynchrone en Python, vous pouvez voir du côté de <a href="http://www.gevent.org/">gevent</a>, <a href="https://github.com/saucelabs/monocle">monocle</a> ou <a href="http://www.tornadoweb.org/en/stable/">Tornado</a>. L&#8217;alternative est d&#8217;utiliser des <a href="http://docs.python.org/2/library/thread.html">threads</a> ou des <a href="http://docs.python.org/2/library/multiprocessing.html?highlight=multiprocessing#multiprocessing">processus séparés</a>, ce qui ne demande rien à installer, mais est un peu verbeux, et est moins performant.</p>
<p>Souvenez-vous que l&#8217;I/O, c&#8217;est toute entrée et sortie du programme. Un clic sur un bouton, c&#8217;est une entrée, mettre à jour un élément du DOM dans le navigateur, c&#8217;est une sortie. La programmation asynchrone est donc importante pour la réactivité des programmes.</p>
<h2>Si un algorithme peut répartir son travail en plusieurs bouts, c&#8217;est parallèle</h2>
<p>Par exemple, vous avez 1000 images en haute définition à traiter : il faut les redimensionner, les mettre en noir et blanc et ajouter une ombre sur les bords. Là, la partie de votre programme qui prend le plus de temps, c&#8217;est le traitement des images, pas l&#8217;I/O, et donc c&#8217;est le CPU. Par exemple, en Python :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">for</span> image <span style="color: #ff7700;font-weight:bold;">in</span> obtenir_liste_images<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
	<span style="color: #808080; font-style: italic;"># I/O</span>
	data = lire_image<span style="color: black;">&#40;</span>image<span style="color: black;">&#41;</span> 
&nbsp;
	<span style="color: #808080; font-style: italic;"># gros du travail</span>
	redimensioner<span style="color: black;">&#40;</span>data<span style="color: black;">&#41;</span>
	mettre_en_noir_et_blanc<span style="color: black;">&#40;</span>data<span style="color: black;">&#41;</span>
	ajouter_ombre<span style="color: black;">&#40;</span>data<span style="color: black;">&#41;</span>
&nbsp;
	<span style="color: #808080; font-style: italic;"># I/O</span>
	ecrire_image<span style="color: black;">&#40;</span>data, image<span style="color: black;">&#41;</span></pre></div></div>

<p>Si vous avez plusieurs ordinateurs, une manière de paralléliser le travail est de mettre 500 images sur l&#8217;un, et 500 images sur l&#8217;autre, et de lancer le script sur chaque ordi.</p>
<p>Si vous avez plusieurs processeurs dans votre ordi (ce qui est le cas de tous les ordis modernes, et plus seulement les super-calculateurs comme il y a 10 ans), vous pouvez aussi paralléliser le travail sur une seule machine : chaque processeur va s&#8217;occuper d&#8217;une partie du taf.</p>
<p>Bien entendu, vous pouvez lancer le script 2 fois, mais cela ne marche que sur des travaux simples comme celui là. Et ça suppose que vous connaissez le nombre de CPU que vous voulez faire travailler à l&#8217;avance.</p>
<p> Une manière de faire plus propre est d&#8217;utiliser des threads ou des processus séparés. En Python, le thread ne servirait à rien, car on se heurterait au GIL, le fameux global interpréteur lock, qui fait qu&#8217;une VM n&#8217;utilise qu&#8217;un processeur, quoi qu&#8217;il arrive. Les threads ne sont donc utiles (en Python), que pour l&#8217;I/O. Par contre on peut utiliser <a href="http://sametmax.com/remplacer-les-threads-avec-le-module-multiprocessing-en-python/">plusieurs processus</a> :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">from</span> multiprocessing <span style="color: #ff7700;font-weight:bold;">import</span> Process
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> traiter_les_images<span style="color: black;">&#40;</span>debut, fin<span style="color: black;">&#41;</span>:
&nbsp;
 <span style="color: #ff7700;font-weight:bold;">for</span> image <span style="color: #ff7700;font-weight:bold;">in</span> obtenir_liste_images<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><span style="color: black;">&#91;</span>debut, fin<span style="color: black;">&#93;</span>:
	<span style="color: #808080; font-style: italic;"># I/O</span>
	data = lire_image<span style="color: black;">&#40;</span>image<span style="color: black;">&#41;</span> 
&nbsp;
	<span style="color: #808080; font-style: italic;"># gros du travail</span>
	redimensioner<span style="color: black;">&#40;</span>data<span style="color: black;">&#41;</span>
	mettre_en_noir_et_blanc<span style="color: black;">&#40;</span>data<span style="color: black;">&#41;</span>
	ajouter_ombre<span style="color: black;">&#40;</span>data<span style="color: black;">&#41;</span>
&nbsp;
	<span style="color: #808080; font-style: italic;"># I/O</span>
	ecrire_image<span style="color: black;">&#40;</span>data, image<span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># On crée deux processus, un pour traiter les 500 premières images,</span>
<span style="color: #808080; font-style: italic;"># un pour traiter les images de 500 à 1000</span>
p1 = Process<span style="color: black;">&#40;</span>target=traiter_les_images, args=<span style="color: black;">&#40;</span><span style="color: #ff4500;">0</span>, <span style="color: #ff4500;">500</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
p2 = Process<span style="color: black;">&#40;</span>target=traiter_les_images, args=<span style="color: black;">&#40;</span><span style="color: #ff4500;">500</span>, <span style="color: #ff4500;">1000</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
<span style="color: #808080; font-style: italic;"># On les démarre, ils se séparent alors du programme pour</span>
<span style="color: #808080; font-style: italic;"># devenir indépendant</span>
p1.<span style="color: black;">start</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
p2.<span style="color: black;">start</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
<span style="color: #808080; font-style: italic;"># on dit au programme d'attendre la fin des deux processus</span>
<span style="color: #808080; font-style: italic;"># CE programme bloque ici, mais les deux processus, eux,</span>
<span style="color: #808080; font-style: italic;"># ne bloquent pas.</span>
p1.<span style="color: black;">join</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
p2.<span style="color: black;">join</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span></pre></div></div>

<p>Dans cet exemple, il y a TROIS processus : votre programme Python, et les deux processus qui vont traiter les photos, qui consistent ni plus ni moins en la fonction <code>traiter_les_images()</code> qui a maintenant un process pour elle toute seule.</p>
<p>La plupart des langages ont ce genre de mécanisme pour faire du travail en parallèle. Java utilise les threads par exemple. Javascript utilise les Web Workers.</p>
<p>Nous traitons des données de plus en plus massives (jeux vidéos, encoding divx, retouche d&#8217;images, montage de sons&#8230;), et maîtriser la parallélisation permet donc d&#8217;optimiser les ressources de nos machines modernes afin d&#8217;être toujours plus efficace.</p>
<h2>Si il y a plusieurs entités indépendantes, c&#8217;est concurrent</h2>
<p>Si vous avez un serveur et un client, c&#8217;est de la programmation concurrente. Si vous avez un module qui s&#8217;occupe des I/O utilisateurs, un qui s&#8217;occupe de la base de données et un qui surveille le comportement de l&#8217;OS, dans des processus séparés, et qui communiquent entre eux, c&#8217;est de la programmation concurrente.</p>
<p>La programmation concurrente suppose que chaque acteur de votre système est indépendant et possède son propre état. Idéalement, les acteurs sont capables de communiquer entre eux. Généralement, ils partagent une ressource à laquelle ils doivent accéder, par exemple un fichier de log. Et c&#8217;est là qu&#8217;il faut faire attention : certaines ressources ne sont pas faites pour êtres utilisées en même temps par plusieurs process. C&#8217;est pour ça qu&#8217;on parle d&#8217;accès concurrent comme d&#8217;un gros problème en informatique.</p>
<p>Un exemple de programmation concurrente en Python serait d&#8217;avoir un process qui regarde régulièrement si il y a des mails, et les sauvegarde. Si il reçoit un message suspect, il envoie le message à un autre process, un anti-virus, qui en plus de surveiller l&#8217;ordi, peut désinfecter le mail. Exemple :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">from</span> multiprocessing <span style="color: #ff7700;font-weight:bold;">import</span> Process, <span style="color: #dc143c;">Queue</span>
&nbsp;
entree_traiteur_de_mail = <span style="color: #dc143c;">Queue</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
entree_anti_virus = <span style="color: #dc143c;">Queue</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> traiter_les_mails<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
&nbsp;
	<span style="color: #808080; font-style: italic;"># Les processus qui tournent continuellement</span>
	<span style="color: #808080; font-style: italic;"># en arrière plan sont juste boucle infinie</span>
	<span style="color: #ff7700;font-weight:bold;">while</span> <span style="color: #008000;">True</span>:
		mail = obtenir_mail<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
		<span style="color: #808080; font-style: italic;"># Si un mail est suspect, on l'envoie</span>
		<span style="color: #808080; font-style: italic;"># au processus de l'anti-virus, </span>
		<span style="color: #808080; font-style: italic;"># et on attend qu'il nous le renvoie</span>
		<span style="color: #808080; font-style: italic;"># tout propres.</span>
		<span style="color: #808080; font-style: italic;"># Les deux processus sont indépendant,</span>
		<span style="color: #808080; font-style: italic;"># ils fonctionnent l'un sans l'autre et</span>
		<span style="color: #808080; font-style: italic;"># ne sont pas dans la même VM.</span>
		<span style="color: #ff7700;font-weight:bold;">if</span> mail_est_suspect<span style="color: black;">&#40;</span>mail<span style="color: black;">&#41;</span>:
			entree_anti_virus.<span style="color: black;">put</span><span style="color: black;">&#40;</span>mail<span style="color: black;">&#41;</span>
			mail = entree_traiteur_de_mail.<span style="color: black;">get</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
		sauvegarder_mail<span style="color: black;">&#40;</span>mail<span style="color: black;">&#41;</span>
&nbsp;
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> anti_virus<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
&nbsp;
	<span style="color: #ff7700;font-weight:bold;">while</span> <span style="color: #008000;">True</span>:
		<span style="color: #808080; font-style: italic;"># L'anti-virus vérifie périodiquement </span>
		<span style="color: #808080; font-style: italic;"># s'il n'a pas un mail à nettoyer,</span>
		<span style="color: #808080; font-style: italic;"># mais n'attend que 0.01 seconde, et si</span>
		<span style="color: #808080; font-style: italic;"># rien ne se présente, continue son </span>
		<span style="color: #808080; font-style: italic;"># travail.</span>
        <span style="color: #ff7700;font-weight:bold;">try</span>:
        	<span style="color: #808080; font-style: italic;"># Si il y a un mail à désinfecter,</span>
        	<span style="color: #808080; font-style: italic;"># il le nettoie, et le renvoie</span>
        	<span style="color: #808080; font-style: italic;"># au processus de traitement de mails.</span>
            mail = entree_anti_virus.<span style="color: black;">get</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">0.01</span><span style="color: black;">&#41;</span>
            desinfecter_mail<span style="color: black;">&#40;</span>mail<span style="color: black;">&#41;</span>
            entree_traiteur_de_mail.<span style="color: black;">put</span><span style="color: black;">&#40;</span>mail<span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">except</span> TimeoutError:
            <span style="color: #ff7700;font-weight:bold;">pass</span>
        <span style="color: #808080; font-style: italic;"># L'anti-virus ne fait pas que desinfecter </span>
        <span style="color: #808080; font-style: italic;"># les mails, il a d'autres tâches à lui</span>
        verifier_virus_sur_system<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
&nbsp;
<span style="color: #808080; font-style: italic;"># On lance les process. La plupart du temps, il n'y a </span>
<span style="color: #808080; font-style: italic;"># pas de mail suspect, et donc les deux processus</span>
<span style="color: #808080; font-style: italic;"># n'en bloquent pas. En cas de mail suspect ils bloquent</span>
<span style="color: #808080; font-style: italic;"># le temps d'échanger le mail entre eux.</span>
process_anti_virus = Process<span style="color: black;">&#40;</span>target=traiter_les_mails<span style="color: black;">&#41;</span>
process_traitement_mail = Process<span style="color: black;">&#40;</span>target=anti_virus<span style="color: black;">&#41;</span>
process_anti_virus.<span style="color: black;">start</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
process_anti_virus.<span style="color: black;">start</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
process_anti_virus.<span style="color: black;">join</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
process_traitement_mail.<span style="color: black;">join</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span></pre></div></div>

<p>La programmation concurrente est donc une question d&#8217;architecture : vous êtes en concurrence ou non si vous décidez de répartir votre code entre plusieurs acteurs indépendant ou non. Les acteurs peuvent avoir des tâches distinctes, et ne pas se bloquer, mais communiquer sur les tâches communes. L&#8217;avantage de la programmation concurrente, c&#8217;est sa robustesse : si un process plante, le reste de votre programme continue de fonctionner. C&#8217;est pour cette raison qu&#8217;Erlang, un langage connu pour créer des systèmes increvables, base toute sa philosophie là dessus : un programme Erlang est composé de milliers d&#8217;acteurs communiquant entre eux par messages.</p>
<h2>Hey, mais, attends là !</h2>
<blockquote><p>Ton exemple de programmation parallèle, c&#8217;est aussi une exécution concurrente. Et puis si on fait pleins de processus, pour faire la même tâche d&#8217;I/O, ils ne se bloquent pas entre eux, donc c&#8217;est non bloquant sur l&#8217;I/O, c&#8217;est asynchrone !</p></blockquote>
<p>Allez-vous me dire, fort intelligement. Car nous avons des lecteurs intelligents.</p>
<p>Hé oui, effectivement, ce sont des notions qui se chevauchent. Comme je vous l&#8217;ai dit, c&#8217;est une question de point de vue. Si on se place du point de vue de l&#8217;algo, on peut paralléliser le traitement, ou non. Et il y a plusieurs manières de paralléliser. Si on se place du point de vu de l&#8217;I/O, on peut bloquer ou non, et alors on est dans de l&#8217;asynchrone. Si on se place du point de vu des acteurs, on peut en avoir plusieurs indépendants ou non, alors on est en concurrence.</p>
<p>En fait, même plusieurs acteurs qui communiquent entre eux sont considérés comme étant chacun en train de faire de l&#8217;I/O, avec les autres&#8230;</p>
<p>Bref, ces 3 termes, c&#8217;est de la sémantiques. Au final, ce qui importe, c&#8217;est que vous compreniez les enjeux qu&#8217;il y a derrière pour écrire un programme qui fasse son boulot comme il faut, et finisse en temps et en heure.</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=7378&amp;md5=2daff4535bf9cc204c43088e47e857b0" title="Flattr" target="_blank"><img src="media/fc229d00.flattr-badge-large.png" data-original-source="http://sametmax.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>


feed_id: http://sametmax.com/?p=7391
title: Si tôt revenu, si tôt repartu
uri: Si-tôt-revenu-si-tôt-repartu
url: http://sametmax.com/si-tot-revenu-si-tot-repartu/
content:
<p>Avec l&#8217;article goulu d&#8217;hier, certains ce sont dit, &#8220;chouette, enfin, les articles forts, beaux et puissants de Sam et Max&#8221; reviennent à la charge.</p>
<p>Mais je suis au regrès de vous annoncer que je me casse pour 4-5 jours pour aller courrir nu dans les bois. Ma bite ne captant pas la 3G, il n&#8217;y aura pas d&#8217;article pendant ce temps.</p>
<p>Donc je vous dis à la semaine&#8230;</p>

<!-- iframe plugin v:2.3 - wordpress.org/extend/plugins/iframe/ -->
<iframe width="420" height="315" src="//www.youtube.com/embed/6B5YK7kujPw#t=173" frameborder="0" scrolling="no" class="iframe-class"></iframe>
<p>&#8230; prochaine !</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=7391&amp;md5=794ebd7646c22efac6c07bdea44bdfed" title="Flattr" target="_blank"><img src="media/fc229d00.flattr-badge-large.png" data-original-source="http://sametmax.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>


feed_id: http://sametmax.com/?p=7435
title: Dites non aux animations 3D
uri: Dites-non-aux-animations-3D
url: http://sametmax.com/dites-non-aux-animations-3d/
content:
<p>Juste parce que vous pouvez ne veut pas dire que vous devez, et le fait que maintenant la plupart des navigateurs supportent des belles transitions 3D ne signifie certainement PAS que vous devriez les utiliser.</p>
<p>En ergonomie, une règle essentielle est de ne pas mettre ou faire de choses qui n&#8217;ont pas de valeur ajoutée pour l&#8217;utilisateur.</p>
<p>L&#8217;esthétique est certes, en soi, une valeur ajoutée. Mais il faut considérer deux choses :</p>
<ul>
<li>Cette technique apporte-t-elle une valeur esthétique qui n&#8217;est pas remplaçable par le bénéfice d&#8217;une autre technique ?</li>
<li>Le bénéfice que mon utilisateur en retire compense-t-il les inconvénients auxquels il est confronté ?</li>
</ul>
<p>Pour les animations 3D, la réponse est clairement NON, dans 99% des cas.</p>
<p>D&#8217;abord, généralement l&#8217;animation est lente, ne serait-ce que pour que le mec devant son écran puisse la voir. Vu le temps qu&#8217;on passe à se faire chier à rendre une app plus rapide et fluide à utiliser, pourquoi voulez-vous, VOLONTAIREMENT et ARTIFICIELLEMENT faire patienter votre utilisateur 400ms de plus devant le slide à cube rotatif pour voir la photo suivante ?</p>
<p>Ensuite, malgré l&#8217;énorme progrès de nos navigateurs, ça bouffe beaucoup de ressources. Bien sûr, quand vous testez sur votre machine quad core avec chrome et un tab ouvert, c&#8217;est parfaitement fluide. Mais il suffit de jouer sur seul de ces paramètres pour que ça ne le soit plus :</p>
<ul>
<li>20 tabs sont ouverts.</li>
<li>Un autre tab utilise Javascript comme un goret (Hello Twitter !).</li>
<li>Un autre tab utilise de la 3D.</li>
<li>Un autre tab charge beaucoup d&#8217;images.</li>
<li>Un autre tab utilise flash.</li>
<li>L&#8217;utilisateur a des logiciels récents sur une vieille machine.</li>
<li>L&#8217;utilisateur utilise d&#8217;autres logiciels que son navigateur qui sollicitent la carte graphique (quelle honte, il ose avoir une vie en dehors de facebook et votre site de merde!).</li>
</ul>
<p>Dans la vraie vie vivante, ce sont plusieurs de ces paramètres qui rentrent en compte, presque systématiquement. Et je ne vais même pas vous parler de ceux qui utilisent IE avec plein de toolbar sur une machine infectée jusqu&#8217;à la moelle. Qui sont, je le rappelle, la majorité des personnes dans le monde. Pas forcément la majorité de votre cible, mais tout de même&#8230;</p>
<p>&#8230;vous êtes une putain de page Web, vous ne pouvez pas pré-supposer de ce que l&#8217;utilisateur fait et dans quel contexte.</p>
<p>Bref, à moins d&#8217;avoir une app avec une connotation visuelle primordiale, par exemple un jeu vidéo, arrêtez avec ces foutues transitions 3D, ça rend votre app inutilisable. Les transitions 2D suffisent largement à améliorer l&#8217;ergonomie et l&#8217;esthétisme d&#8217;une page, et elles bouffent beaucoup moins.</p>
<p>Merci</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=7435&amp;md5=ca53e86d6abbc9ce51ab8529089f5dd6" title="Flattr" target="_blank"><img src="media/fc229d00.flattr-badge-large.png" data-original-source="http://sametmax.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>


feed_id: http://sametmax.com/?p=7448
title: Les time zones en Python
uri: Les-time-zones-en-Python
url: http://sametmax.com/les-time-zones-en-python/
content:
<p>Si vous suivez un peu le blog, vous savez <a href="http://sametmax.com/manipuler-les-dates-et-les-durees-en-python/">comment manipuler les dates en Python</a>. Et c&#8217;est trop cool. Parce que le temps, c&#8217;est quelque chose de difficile en programmation, comme la gestion des monnaies ou la traduction d&#8217;une interface.</p>
<p>Mais notre article ne traite pas des time zones, c&#8217;est à dire de la gestion des fuseaux horaires. La raison est très simple, Sam est une grosse feignasse, et comme c&#8217;est un sujet <a href="http://lucumr.pocoo.org/2011/7/15/eppur-si-muove/">super galère</a>, il l&#8217;a soigneusement évité, vous renvoyant à l&#8217;usage de pytz. Démerdez vous.</p>
<p>Qu&#8217;est-ce qui a changé ? Le sujet est-il devenu plus simple ? Sam a-t-il un regain de motivation ? Le fait de parler de lui à la 3eme personne est-il signe de sénilité ?</p>
<p>Bien sûr que non, c&#8217;est simplement que je suis tombé sur <a href="http://crsmithdev.com/arrow/">arrow</a>, une lib Python qui résout le problème. Pour faire simple, c&#8217;est presque exactement la lib que j&#8217;avais commencé à coder pour la gestion du temps. Sauf que le mec, lui, il l&#8217;a terminé, alors que la mienne, elle est au fin fond d&#8217;un repo git poussiéreux depuis 8 mois.</p>
<p>Bref, laissez tout tomber, n&#8217;installez plus dateutil, pytz et autres libs que j&#8217;ai pu vous recommander par le passé (elle sont incluses et abstraites par arrow). Faites juste :</p>
<p><code>pip install arrow</code></p>
<h2>Tout commence par l&#8217;UTC</h2>
<p>Comme pour la gestion des encodings, la gestion des dates se fait en utilisant une base commune. Pour l&#8217;encoding, c&#8217;est unicode, pour les dates, c&#8217;est UTC.</p>
<p>Donc, si vous prévoyez de gérer différents fuseaux horaires dans votre programme, TOUT votre programme &#8211; j&#8217;ai dit TOUT &#8211; doit manipuler exclusivement des dates en UTC.</p>
<p>Comme avec l&#8217;encoding, l&#8217;idée est la suivante :</p>
<ul>
<li>A l&#8217;entrée de votre programme, vous acceptez des dates avec une timezone. Vous convertissez ces dates vers l&#8217;UTC.</li>
<li>Dans votre programme, vous manipuler uniquement de l&#8217;UTC.</li>
<li>A la sortie du programme, vous renvoyez des dates dans une timezone.</li>
</ul>
<p>Ceci suppose donc que :</p>
<ul>
<li>Vous savez ce qu&#8217;est une entrée et une sortie. Je vous fait un rappel : tout ce qui est pas dans votre programme (query base de données, socket, fichiers, print, input utilisateur, clic, affichage, etc.).</li>
<li>Vous DEVEZ savoir la timezone de ce qui rentre. <strong>Si vous ne le savez pas, vous ne pouvez absolument rien faire</strong> à part afficher à votre utilisateur que vous ne savez pas et le réglage par défaut . Pour la sortie, si vous ne savez pas, vous pouvez sortir de l&#8217;UTC par défaut, ça mange pas de pain. Mais pour l&#8217;entrée, il faut lire la spec, la doc, demandé au collègue, au fournisseur, au client, peut importe, il faut trouver l&#8217;info.</li>
</ul>
<h2>Avec arrow, c&#8217;est simplissime&#8230;</h2>
<p>Si vous créez une date vous même, il suffit de toujours le faire en UTC :</p>

<div class="wp_syntax"><div 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> arrow
<span style="color: #66cc66;">&gt;&gt;&gt;</span> maintenant = arrow.<span style="color: black;">utcnow</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span> <span style="color: #808080; font-style: italic;"># heure et date actuelle en UTC</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span>maintenant<span style="color: black;">&#41;</span>
<span style="color: #ff4500;">2013</span>-<span style="color: #ff4500;">10</span>-15T17:<span style="color: #ff4500;">15</span>:<span style="color: #ff4500;">19.139000</span>+00:00
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #ff7700;font-weight:bold;">from</span> <span style="color: #dc143c;">datetime</span> <span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">datetime</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> date_de_sortie_des_goonies = arrow.<span style="color: black;">get</span><span style="color: black;">&#40;</span><span style="color: #dc143c;">datetime</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">1985</span>, <span style="color: #ff4500;">12</span>, <span style="color: #ff4500;">4</span><span style="color: black;">&#41;</span>, <span style="color: #483d8b;">'US/Pacific'</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: black;">&#40;</span>date_de_sortie_des_goonies<span style="color: black;">&#41;</span>
<span style="color: #ff4500;">1985</span>-<span style="color: #ff4500;">12</span>-04T00:00:00-08:00
<span style="color: #66cc66;">&gt;&gt;&gt;</span> date_de_sortie_des_goonies = date_de_sortie_des_goonies.<span style="color: black;">to</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'utc'</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: black;">&#40;</span>date_de_sortie_des_goonies<span style="color: black;">&#41;</span>
<span style="color: #ff4500;">1985</span>-<span style="color: #ff4500;">12</span>-04T08:00:00+00:00
Là, on a des dates uniquements en UTC.</pre></div></div>

<p>Si vous importez une date, c&#8217;est très simple également :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">&gt;&gt;&gt;</span> arrow.<span style="color: black;">get</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">1367900664</span><span style="color: black;">&#41;</span> <span style="color: #808080; font-style: italic;"># un timestamp marche..</span>
<span style="color: #66cc66;">&lt;</span>Arrow <span style="color: black;">&#91;</span><span style="color: #ff4500;">2013</span>-05-07T04:<span style="color: #ff4500;">24</span>:<span style="color: #ff4500;">24</span>+00:00<span style="color: black;">&#93;</span><span style="color: #66cc66;">&gt;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> arrow.<span style="color: black;">get</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'1367900664'</span><span style="color: black;">&#41;</span> <span style="color: #808080; font-style: italic;"># ... même en string</span>
<span style="color: #66cc66;">&lt;</span>Arrow <span style="color: black;">&#91;</span><span style="color: #ff4500;">2013</span>-05-07T04:<span style="color: #ff4500;">24</span>:<span style="color: #ff4500;">24</span>+00:00<span style="color: black;">&#93;</span><span style="color: #66cc66;">&gt;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> arrow.<span style="color: black;">get</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">1367900664.152325</span><span style="color: black;">&#41;</span> <span style="color: #808080; font-style: italic;"># ... ou en float</span>
<span style="color: #66cc66;">&lt;</span>Arrow <span style="color: black;">&#91;</span><span style="color: #ff4500;">2013</span>-05-07T04:<span style="color: #ff4500;">24</span>:<span style="color: #ff4500;">24.152325</span>+00:00<span style="color: black;">&#93;</span><span style="color: #66cc66;">&gt;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> arrow.<span style="color: black;">get</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'2013-09-30T15:34:00.000-07:00'</span><span style="color: black;">&#41;</span>.<span style="color: black;">to</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'utc'</span><span style="color: black;">&#41;</span> <span style="color: #808080; font-style: italic;"># parser une date standard...</span>
<span style="color: #66cc66;">&lt;</span>Arrow <span style="color: black;">&#91;</span><span style="color: #ff4500;">2013</span>-09-30T22:<span style="color: #ff4500;">34</span>:00+00:00<span style="color: black;">&#93;</span><span style="color: #66cc66;">&gt;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #ff7700;font-weight:bold;">from</span> dateutil <span style="color: #ff7700;font-weight:bold;">import</span> tz <span style="color: #808080; font-style: italic;"># pour parser une date custo</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> arrow.<span style="color: black;">Arrow</span>.<span style="color: black;">strptime</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'2013-05-05 12:30:45'</span>, <span style="color: #483d8b;">'%Y-%m-%d %H:%M:%S'</span>, tz.<span style="color: black;">gettz</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'Paris/Europe'</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
<span style="color: #66cc66;">&lt;</span>Arrow <span style="color: black;">&#91;</span><span style="color: #ff4500;">2013</span>-05-05T12:<span style="color: #ff4500;">30</span>:<span style="color: #ff4500;">45</span>+00:00<span style="color: black;">&#93;</span><span style="color: #66cc66;">&gt;</span></pre></div></div>

<p>Tout ça renvoie de l&#8217;UTC. </p>
<p>Et quand vous voulez afficher une date, vous pouvez tout simplement la reconvertir vers la timezone de votre choix avec la méthode <code>to()</code> et la formater comme avec <code>format()</code></p>
<h2>Stockage des dates</h2>
<p>Quand on stocke une date (dans une base de données, un fichier, etc), il faut se demander quel est le but du stockage. Si le but est de stocker la date d&#8217;un événement, mettez la date en UTC. Un timestamp suffit, ou alors la représentation YYYY-MM-DD hh:mm:ss. Par contre, si vous voulez stocker une date liée à un événement et un lieu (par exemple un rendez-vous d&#8217;affaire ou le décollage d&#8217;un avion), stockez la date en UTC avec sa timezone dans un champ à côté, sinon vous serez bien baisé quand vous voudrez la ressortir.</p>
<p>Ah oui, et réglez toujours tous vos serveurs sur UTC. Toujours.</p>
<h2>En bonus</h2>
<p>On peut obtenir toutes les infos utiles sans tourner autour du pot :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">&gt;&gt;&gt;</span> a = arrow.<span style="color: black;">utcnow</span><span style="color: black;">&#40;</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: black;">&#40;</span>a.<span style="color: #dc143c;">datetime</span><span style="color: black;">&#41;</span>
<span style="color: #ff4500;">2013</span>-<span style="color: #ff4500;">10</span>-<span style="color: #ff4500;">15</span> <span style="color: #ff4500;">17</span>:<span style="color: #ff4500;">48</span>:<span style="color: #ff4500;">28.335000</span>+00:00
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span>a.<span style="color: black;">timestamp</span><span style="color: black;">&#41;</span>
<span style="color: #ff4500;">1381859308</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <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>a.<span style="color: black;">naive</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span> <span style="color: #808080; font-style: italic;"># on accès à l'objet datetime au cas où...</span>
<span style="color: #dc143c;">datetime</span>.<span style="color: #dc143c;">datetime</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">2013</span>, <span style="color: #ff4500;">10</span>, <span style="color: #ff4500;">15</span>, <span style="color: #ff4500;">17</span>, <span style="color: #ff4500;">49</span>, <span style="color: #ff4500;">25</span>, <span style="color: #ff4500;">515000</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: black;">&#40;</span>a.<span style="color: black;">tzinfo</span><span style="color: black;">&#41;</span> <span style="color: #808080; font-style: italic;"># ... et à l'objet tzinfo</span>
tzutc<span style="color: black;">&#40;</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: black;">&#40;</span>a.<span style="color: black;">year</span>, a.<span style="color: black;">hour</span><span style="color: black;">&#41;</span>
<span style="color: black;">&#40;</span><span style="color: #ff4500;">2013</span>, <span style="color: #ff4500;">17</span><span style="color: black;">&#41;</span></pre></div></div>

<p>Et on peut faire des replacements et des calculs flous, comme avec dateutil :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">&gt;&gt;&gt;</span> a = arrow.<span style="color: black;">utcnow</span><span style="color: black;">&#40;</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: black;">&#40;</span>a.<span style="color: black;">format</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'DD, MMMM'</span>, <span style="color: #dc143c;">locale</span>=<span style="color: #483d8b;">'fr_FR'</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
<span style="color: #ff4500;">15</span>, Octobre
<span style="color: #66cc66;">&gt;&gt;&gt;</span> a = a.<span style="color: black;">replace</span><span style="color: black;">&#40;</span>day=<span style="color: #ff4500;">30</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: black;">&#40;</span>a.<span style="color: black;">format</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'DD, MMMM'</span>, <span style="color: #dc143c;">locale</span>=<span style="color: #483d8b;">'fr_FR'</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
<span style="color: #ff4500;">30</span>, Octobre
<span style="color: #66cc66;">&gt;&gt;&gt;</span> a = a.<span style="color: black;">replace</span><span style="color: black;">&#40;</span>days=+<span style="color: #ff4500;">1</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: black;">&#40;</span>a.<span style="color: black;">format</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'DD, MMMM'</span>, <span style="color: #dc143c;">locale</span>=<span style="color: #483d8b;">'fr_FR'</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
<span style="color: #ff4500;">31</span>, Octobre
<span style="color: #66cc66;">&gt;&gt;&gt;</span> a = a.<span style="color: black;">replace</span><span style="color: black;">&#40;</span>months=-<span style="color: #ff4500;">1</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: black;">&#40;</span>a.<span style="color: black;">format</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'DD, MMMM'</span>, <span style="color: #dc143c;">locale</span>=<span style="color: #483d8b;">'fr_FR'</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
<span style="color: #ff4500;">30</span>, Septembre</pre></div></div>

<p>Faire de l&#8217;affichage relatif :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">&gt;&gt;&gt;</span> before = arrow.<span style="color: black;">utcnow</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>.<span style="color: black;">replace</span><span style="color: black;">&#40;</span>hours=-<span style="color: #ff4500;">3</span><span style="color: black;">&#41;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> before.<span style="color: black;">humanize</span><span style="color: black;">&#40;</span><span style="color: #dc143c;">locale</span>=<span style="color: #483d8b;">'Fr_fr'</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
<span style="color: #483d8b;">'il y a 3 heures'</span></pre></div></div>

<p>Bref, arrow, c&#8217;est de la bombe baby !</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=7448&amp;md5=8544577e57bf6731aa84ee26834f36c2" title="Flattr" target="_blank"><img src="media/fc229d00.flattr-badge-large.png" data-original-source="http://sametmax.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>


feed_id: http://sametmax.com/?p=7458
title: 10 excellents films peu connus
uri: 10-excellents-films-peu-connus
url: http://sametmax.com/10-excellents-films-peu-connus/
content:
<p>Après <a href="http://sametmax.com/10-excellentes-series-peu-connues/">la thématique des séries</a>, petite aparté pour parler de 10 films qui méritent de votre temps, en cette époque où tellement de bouses essayent de vous le faire perdre en vous faisant payer pour ça.</p>
<h2>Dogma</h2>
<p><a href="http://www.imdb.com/title/tt0120655/?ref_=fn_al_tt_1">Ce film</a> est l&#8217;archétype du bijou inconnu.</p>
<p>D&#8217;abord, un casting monstrueux : Matt Damon, Ben Affleck, Alan Rickman, Chris Rock et Alanis Morissette (qui joue Dieu, si si).</p>
<p>Ensuite, un scénario complètement barré : Dieu (qui est une femme), a disparu. Deux anges qui ont tendance à massacrer un peu tout ce qui passe vont tenter d&#8217;en profiter pour baiser le système, ce qui pourrait causer quelques souci dans la stabilité du monde. Du coup on envoie le 13eme prophète, un oublié de la Bible parce qu&#8217;il est noir, filer un coup de main à la petite-petite-petite descendante de Jésus pour rétablir tout ça.</p>
<p>Les dialogues sont fantastiques, les personnages sont tous uniques et hauts en couleurs. Ai-je mentionné que c&#8217;était drôle ?</p>

<!-- iframe plugin v:2.3 - wordpress.org/extend/plugins/iframe/ -->
<iframe width="560" height="315" src="//www.youtube.com/embed/6FigprdcBGA" frameborder="0" scrolling="no" class="iframe-class"></iframe>
<h2>Le prestige</h2>
<p>Bien avant de faire the Dark Knight, Christopher Nolan était déjà un réalisateur de génie avec des films uniques comme <a href="http://www.imdb.com/title/tt0209144/?ref_=fn_al_tt_1">Memento</a>. Mais bien au dessus de tout ça, bien au dessus de tous ses films en fait, se trouve le <a href="http://www.imdb.com/title/tt0482571/?ref_=fn_al_tt_1">Prestige</a>.</p>
<p>Déjà vous avez Wolverine et Batman dedans, et ça, ça claque. Et surtout, vous allez être embarqués dans une histoire que vous ne pourrez prédire à aucun moment. Aucun cliché, aucune manière de prédire ce qui va arriver. Vous allez vous enrichir, apprendre, et plonger dans les méandres de ce scénarios pourtant très simple, mais intensément mis en scène. Un duel entre deux prestidigitateurs s&#8217;étale sur plusieurs années, et vous allez découvrir, pas à pas, le prix du prestige.</p>

<!-- iframe plugin v:2.3 - wordpress.org/extend/plugins/iframe/ -->
<iframe width="560" height="315" src="//www.youtube.com/embed/qhGULSvtDO4" frameborder="0" scrolling="no" class="iframe-class"></iframe>
<h2>Chat noir, chat blanc</h2>
<p><a href="http://www.imdb.com/title/tt0118843/?ref_=fn_al_tt_1">C&#8217;est Serbes</a>, c&#8217;est barré, c&#8217;est joyeux, c&#8217;est hyper dynamique et ça vous prend complètement au dépourvu. Attaque de trains d&#8217;essence, mariage forcé, jongle avec des grenades, suicide et résurrection. Les rebondissements ne s&#8217;arrêtent jamais, le tout dans une bande son qui va vous faire danser la Mouchkivtche Blévédienne.</p>
<p>Si vous avez besoin d&#8217;un dépaysement, c&#8217;est le moment.</p>

<!-- iframe plugin v:2.3 - wordpress.org/extend/plugins/iframe/ -->
<iframe width="420" height="315" src="//www.youtube.com/embed/CkoQcLgquWI" frameborder="0" scrolling="no" class="iframe-class"></iframe>
<h2>La cité des enfants perdus</h2>
<p>Les gens connaissent Jeunet pour Amélie Poulain, et parfois, pour <a href="http://www.imdb.com/title/tt0101700/?ref_=fn_al_tt_1">Delicatessen</a>. Beaucoup plus rarement pour le étonnement bon Alien 4. Et quasiment jamais pour <a href="http://www.imdb.com/title/tt0112682/?ref_=fn_al_tt_1">la cité des enfants perdus</a>.</p>
<p>Chef d’œuvre visuel, je ne vous le recommanderais néanmoins pas durant les phases de déprime, car c&#8217;est un film très glauque, une marrais cinématographique psychologiquement violent, parfois dur à encaisser : un vieux scientifique vivant sur une plateforme pétrolière entourée de mines marines et de ses clones plus ou moins ratés, n&#8217;arrive pas à rêver. Pour y pallier, il kidnappe des nouveaux nés et tente de leur voler leurs rêves, n&#8217;obtenant que des cauchemar. Une frêle fille maline et un géant un peu bête trouvent une cause commune pour aller s&#8217;y aventurer&#8230;</p>

<!-- iframe plugin v:2.3 - wordpress.org/extend/plugins/iframe/ -->
<iframe width="560" height="315" src="//www.youtube.com/embed/FOJ6UGp8dj4" frameborder="0" scrolling="no" class="iframe-class"></iframe>
<h2>Les Looney Tunes passent à l&#8217;action</h2>
<p>Je m&#8217;attendais à un Space Jam, et <a href="http://www.imdb.com/title/tt0318155/?ref_=fn_al_tt_3">je suis tombé</a> sur un Qui veut la peau de Roger Rabbit. Comme quoi il reste parfois un soupçon de créativité chez les majors. Mais vraiment au fond de l&#8217;assiette, hein.</p>
<p>Bref, c&#8217;est du dessin animé incrusté dans du film, à la Mary Poppins / l&#8217;Apprentie sorcière / Peter et Eliot le dragon. Les bons trucs à l&#8217;ancienne quoi. Mais modernisé. C&#8217;est cartoonesque dans l&#8217;hum(o|e)ur, avec pas mal d&#8217;auto-dérision sur Warner Bros, les grosses compagnies en général et les block busters en particulier.</p>

<!-- iframe plugin v:2.3 - wordpress.org/extend/plugins/iframe/ -->
<iframe width="560" height="315" src="//www.youtube.com/embed/3uuNGbMsb1A" frameborder="0" scrolling="no" class="iframe-class"></iframe>
<h2>Jusqu&#8217;en enfer</h2>
<p>J&#8217;ai hésité à mettre <a href="http://www.imdb.com/title/tt0450385/?ref_=fn_al_tt_1">Chambre 1408</a>, mais ce dernier (comme beaucoup de bons films avec Cusack genre <a href="http://www.imdb.com/title/tt0884224/?ref_=fn_al_tt_1">War, inc</a>&#8230;), n&#8217;est pas un film qui fait peur. Or je voulais faire un top 10 un peu diversifié. Mais franchement, combien de films d&#8217;horreur font peur ? Presque aucun. En fait, la scène de Dumbo bourré (si, si, regardez à nouveau le film&#8230;) m&#8217;a bien plus effrayé que les merdes d&#8217;Insidious ou Paranormal activity. Et certes, Chucky, Jason, L&#8217;exorciste ou Freddy sont des classiques géniaux. Mais ils ne font pas vraiment peur. Même les bonnes surprises récentes (hello la cabanes dans les bois !) sont divertissantes, pas effrayantes.</p>
<p><a href="http://www.imdb.com/title/tt1127180/?ref_=fn_al_tt_1">Jusqu&#8217;en enfer</a> m&#8217;a fait sursauté bien des fois. J&#8217;ai vraiment senti l&#8217;angoisse s&#8217;installer, j&#8217;ai senti la panique des personnages, j&#8217;ai été trainé dans la spirale maléfique de ce film là où Dark Water m&#8217;a vainement tiré un bâillement.</p>
<p>Le scénario a en fait peu d&#8217;importance. Ce qui est génial, c&#8217;est le rythme. La descente. La progression lugubre bien maîtrisé, avec une subtilité que les productions américaines ont rarement. Et des acteurs qui soutiennent chaque plan, car il n&#8217;y a rien de plus facile à raté qu&#8217;une scène où l&#8217;on joue la terreur. Ce film est brillant de par sa progression : il commence tranquillement, et vous prend par derrière au plus mauvais moment. Même quand vous vous y attendez, il n&#8217;y a rien à faire.</p>
<p>Et hop, le film est en entier sur Tutube :</p>

<!-- iframe plugin v:2.3 - wordpress.org/extend/plugins/iframe/ -->
<iframe width="560" height="315" src="//www.youtube.com/embed/chsF8xwVTmE" frameborder="0" scrolling="no" class="iframe-class"></iframe>
<h2>Explorers</h2>
<p>A cheval entre les Goonies et Jumanji, ce film qui a un poil vieilli va vous servir de madeleine des années 80. Souvenez-vous : retour vers le future, ghostbuster, gremlins, et des réalisateurs qui ne violaient pas encore les symboles de la jeunesse de leur public avec des Super 8 et Indiana Jones 4.</p>
<p><a href="http://www.imdb.com/title/tt0089114/?ref_=fn_al_tt_1">Explorers</a>, ce sont des gamins qui rêvent d&#8217;un plan de circuit electronique, et qui le construisent, pour s&#8217;apercevoir qu&#8217;il peut générer une bulle dans laquelle ont ne ressent aucune inertie, et qui peut traverser toute matière, se déplaçant avec peu d&#8217;énergie, transportant un fort poids. Et là commence une bonne aventure old school, avec des gosses bordéliques (franchement, vous avez vu les chambres bien rangés qu&#8217;ils ont dans les films actuels les gamins ?) avec des réactions de gosses et des préoccupations de gosses. Pas d&#8217;ados, pas de faux adultes. De gosses. Et des costumes ridicules.</p>

<!-- iframe plugin v:2.3 - wordpress.org/extend/plugins/iframe/ -->
<iframe width="420" height="315" src="//www.youtube.com/embed/3X3VxBJzH68" frameborder="0" scrolling="no" class="iframe-class"></iframe>
<h2>Atomik Circus</h2>
<p>Si je ne peux pas vraiment vous décrire ce qu&#8217;est <a href="http://www.imdb.com/title/tt0362084/?ref_=fn_al_tt_1">Atomik Circus</a>, c&#8217;est parce que je m&#8217;en sens incapable. Ce film n&#8217;appartient à aucun genre, ne suis pas vraiment de logique, et n&#8217;a pas le goût de quoique ce soit de testé auparavant.</p>
<p>Dire pourquoi j&#8217;aime ce film me semble relever tout autant de impossibilité rédactionnelle : l&#8217;ambiance unique ? L&#8217;humour (très) noir ? Le côté imprévisible ? Les personnages tarés ?</p>
<p>Attendez, je vous traduis le résumé de IMDB, vous allez comprendre ce que je veux dire :</p>
<blockquote><p>James Bataille s&#8217;échappe de prison pour retrouver sa fiancée Concia. Mais à son retour des poulpes aliens viennent jouer un jeu de massacre. Après une bataille bien chanceuse, James et Concia s&#8217;échappent dans un monde parallèle.</p></blockquote>
<p>Et bien sachez mes amis, que ceci, bien que somme toute correcte, ne vous apprend RIEN sur le film. Et j&#8217;en veux pour preuve cet extrait :</p>
<p><iframe width="420" height="315" src="//www.youtube.com/embed/BkhplpjWHXk" frameborder="0" allowfullscreen></iframe></p>
<p>Tentez le coup. Avec des amis ouverts d&#8217;esprit :-)</p>
<h2>Heathers</h2>
<p>Ah, les teen movies. Ça ne peut pas être bon pas vrai ? Je veux dire, on en a bouffé du vampire, du loup garou, des demi-machin et des abrutis complets. A croire que le genre est maudis !</p>
<p>Mais pas du tout ! Le péril jeune, <a href="http://www.imdb.com/title/tt0088847/?ref_=fn_al_tt_1">The Breakfast club</a> et <a href="http://www.imdb.com/title/tt0091042/?ref_=fn_al_tt_4">Ferris Bueller&#8217;s Day Off</a> prouvent au contraire qu&#8217;on peut taper dans l&#8217;ado ET être intéressant. L&#8217;astuce, c&#8217;est de considérer les mineurs comme des être humains, comme les femmes, les juifs et les autistes.</p>
<p>Et la palme des répliques les plus trash revient à&#8230;.</p>
<blockquote><p>Fuck me gently with a chain saw</p></blockquote>
<p><iframe width="560" height="315" src="//www.youtube.com/embed/LQ-3rikUQ34" frameborder="0" allowfullscreen></iframe></p>
<h2>La peur au ventre</h2>
<p>Comment trouver un comparatif pour <a href="http://www.imdb.com/title/tt0404390/?ref_=fn_al_tt_1">La peur au ventre</a>. Pour le rythme, je pourrais invoquer les merveilleux Arnaque, crime, et botanique, Slevin ou Snatch. Clairement, il y aussi une inspiration d&#8217;Alice au pays des merveilles (restez pour le générique de fin, ça vaut le coup) pour le côté fuite dans un monde délirant. Et pour le côté transgressif et dépaysant, peut être un peu du surprenant <a href="http://www.imdb.com/title/tt0364569/?ref_=fn_al_tt_1">Old Boy</a>.</p>
<p>Je ne m&#8217;attendais pas du tout, mais alors, pas du tout, à ce que la peur au ventre me plaise. Mon pote me l&#8217;avait très mal vendu, et le synopsis est à chier.</p>
<p>Mais voilà, encore un scénariste qui a travaillé ses rebondissements et ses personnages. Encore des acteurs qui prennent leurs rôles très à cœur. Et une petit touche de magie qui donne à ce thriller une atmosphère bien à lui, de la personnalité et de la force.</p>
<p>Allez, finissons ce billet avec un peu de pédophilie, sinon on ne serait pas sur Sam et Max :</p>

<!-- iframe plugin v:2.3 - wordpress.org/extend/plugins/iframe/ -->
<iframe width="560" height="315" src="//www.youtube.com/embed/Nrz-h8sU85A" frameborder="0" scrolling="no" class="iframe-class"></iframe>
<p>Par contre les commentaires les plus populaires sur youtube sont vraiment flippant.</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=7458&amp;md5=7fae130403802209514c3c3d16731caf" title="Flattr" target="_blank"><img src="media/fc229d00.flattr-badge-large.png" data-original-source="http://sametmax.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>


feed_id: http://sametmax.com/?p=7469
title: Ouvrir un fichier avec le bon programme en Python
uri: Ouvrir-un-fichier-avec-le-bon-programme-en-Python
url: http://sametmax.com/ouvrir-un-fichier-avec-le-bon-programme-en-python/
content:
<p>Votre logiciel doit permettre d&#8217;ouvrir un fichier avec un programme externe. Oui mais lequel ?</p>
<p>Les OS ont des réglages par défaut pour chaque type de fichier, et on peut demander &#8220;ouvrir le prog pour ce type de fichier par défaut&#8221;. Par exemple, moi, si je demande d&#8217;ouvrir un fichier vidéo, je m&#8217;attend à ce que VLC soit lancé.</p>
<p>Voilà comment faire ça en Python :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">subprocess</span>
<span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">sys</span>
<span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">os</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> run_file<span style="color: black;">&#40;</span>path<span style="color: black;">&#41;</span>:
&nbsp;
    <span style="color: #808080; font-style: italic;"># Pas de EAFP cette fois puisqu'on est dans un process externe,</span>
    <span style="color: #808080; font-style: italic;"># on ne peut pas gérer l'exception aussi facilement, donc on fait</span>
    <span style="color: #808080; font-style: italic;"># des checks essentiels avant.</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># Vérifier que le fichier existe</span>
    <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #ff7700;font-weight:bold;">not</span> <span style="color: #dc143c;">os</span>.<span style="color: black;">path</span>.<span style="color: black;">exists</span><span style="color: black;">&#40;</span>path<span style="color: black;">&#41;</span>:
        <span style="color: #ff7700;font-weight:bold;">raise</span> <span style="color: #008000;">IOError</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'No such file: %s'</span> <span style="color: #66cc66;">%</span> path<span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># On a accès en lecture ?</span>
    <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #008000;">hasattr</span><span style="color: black;">&#40;</span><span style="color: #dc143c;">os</span>, <span style="color: #483d8b;">'access'</span><span style="color: black;">&#41;</span> <span style="color: #ff7700;font-weight:bold;">and</span> <span style="color: #ff7700;font-weight:bold;">not</span> <span style="color: #dc143c;">os</span>.<span style="color: black;">access</span><span style="color: black;">&#40;</span>path, <span style="color: #dc143c;">os</span>.<span style="color: black;">R_OK</span><span style="color: black;">&#41;</span>:
        <span style="color: #ff7700;font-weight:bold;">raise</span> <span style="color: #008000;">IOError</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'Cannot access file: %s'</span> <span style="color: #66cc66;">%</span> path<span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># Lancer le bon programme pour le bon OS :</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #008000;">hasattr</span><span style="color: black;">&#40;</span><span style="color: #dc143c;">os</span>, <span style="color: #483d8b;">'startfile'</span><span style="color: black;">&#41;</span>: <span style="color: #808080; font-style: italic;"># Windows</span>
        <span style="color: #808080; font-style: italic;"># Startfile est très limité sous Windows, on ne pourra pas savoir</span>
        <span style="color: #808080; font-style: italic;"># si il y a eu une erreu</span>
        proc = <span style="color: #dc143c;">os</span>.<span style="color: black;">startfile</span><span style="color: black;">&#40;</span>path<span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">elif</span> <span style="color: #dc143c;">sys</span>.<span style="color: #dc143c;">platform</span>.<span style="color: black;">startswith</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'linux'</span><span style="color: black;">&#41;</span>: <span style="color: #808080; font-style: italic;"># Linux:</span>
        proc = <span style="color: #dc143c;">subprocess</span>.<span style="color: black;">Popen</span><span style="color: black;">&#40;</span><span style="color: black;">&#91;</span><span style="color: #483d8b;">'xdg-open'</span>, path<span style="color: black;">&#93;</span>, 
                                 <span style="color: #808080; font-style: italic;"># on capture stdin et out pour rendre le </span>
                                 <span style="color: #808080; font-style: italic;"># tout non bloquant</span>
                                 stdout=<span style="color: #dc143c;">subprocess</span>.<span style="color: black;">PIPE</span>, stderr=<span style="color: #dc143c;">subprocess</span>.<span style="color: black;">PIPE</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">elif</span> <span style="color: #dc143c;">sys</span>.<span style="color: #dc143c;">platform</span> == <span style="color: #483d8b;">'darwin'</span>: <span style="color: #808080; font-style: italic;"># Mac:</span>
        proc = <span style="color: #dc143c;">subprocess</span>.<span style="color: black;">Popen</span><span style="color: black;">&#40;</span><span style="color: black;">&#91;</span><span style="color: #483d8b;">'open'</span>, <span style="color: #483d8b;">'--'</span>, path<span style="color: black;">&#93;</span>, 
                                stdout=<span style="color: #dc143c;">subprocess</span>.<span style="color: black;">PIPE</span>, stderr=<span style="color: #dc143c;">subprocess</span>.<span style="color: black;">PIPE</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">else</span>:
        <span style="color: #ff7700;font-weight:bold;">raise</span> <span style="color: #008000;">NotImplementedError</span><span style="color: black;">&#40;</span>
            <span style="color: #483d8b;">&quot;Your `%s` isn't a supported operatin system`.&quot;</span> <span style="color: #66cc66;">%</span> <span style="color: #dc143c;">sys</span>.<span style="color: #dc143c;">platform</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># Proc sera toujours None sous Windows. Sous les autres OS, il permet de</span>
    <span style="color: #808080; font-style: italic;"># récupérer le status code du programme, and lire / ecrire sur stdin et out</span>
    <span style="color: #ff7700;font-weight:bold;">return</span> proc</pre></div></div>

<p>C&#8217;était le petit snippet sympas du jour !</p>
<p>P.S : si quelqu&#8217;un utilise <del>BDSM</del> BSD ou Solaris, je veux bien qu&#8217;il complète le snippet.</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=7469&amp;md5=805b865a7efd4cc59774fee70bfd710e" title="Flattr" target="_blank"><img src="media/fc229d00.flattr-badge-large.png" data-original-source="http://sametmax.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>


feed_id: http://sametmax.com/?p=7473
title: Locked out from twitter
uri: Locked-out-from-twitter
url: http://sametmax.com/locked-out-from-twitter/
content:
<p>Hier, on a été accueilli par ça :</p>
<pre>
Sapristi ! Attendez un peu avant d'essayer de vous connecter de nouveau.

Pour éviter les abus, nous limitons le nombre de tentatives de connexion par heure.

Si le mot de passe de votre compte a été changé récemment, assurez-vous que toutes les applications tierces et tous les clients Twitter soient fermés avant de tenter de vous connecter à nouveau. Pour plus d'informations, veuillez consulter cet article d'aide.

Veuillez réessayer dans 60 minutes.
</pre>
<p>Donc je suppose que qu&#8217;un service quelconque s&#8217;est fait hacké, avec notre email dedans, et qu&#8217;un bot a défoncé notre compte twitté en tentant le bruteforce avec des variations du mot de passe du compte précédent. Bref, une bonne raison de plus d&#8217;utiliser lastpass pour générer des mots de passe pour chaque servie.</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=7473&amp;md5=48c6746180695cfae192ccaffcb0a85e" title="Flattr" target="_blank"><img src="media/fc229d00.flattr-badge-large.png" data-original-source="http://sametmax.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>


feed_id: http://sametmax.com/?p=7442
title: Dans les règles du lard
uri: Dans-les-règles-du-lard
url: http://sametmax.com/dans-les-regles-du-lard/
content:
<p>Il y a une scène que j&#8217;adore dans Californation, c&#8217;est au premier épisode, quand le principal protagoniste est (pour changer) au lit avec une donzelle, qui lui dit qu&#8217;aujourdhui elle ne peut pas. Ca donne :</p>
<ul>
<li>We can&#8217;t it&#8217;s dirty, dit la jeune effarouchée avec un air déçu.</li>
<li>Yes, it&#8217;s dirty&#8230; rétorque Hank, avec un air de satyre en lui sautant dessus.</li>
</ul>
<p>Pour moi c&#8217;est un peu pareil, je trouve les proverbes du genre &#8220;quand coule la rivière du sang emprunte le petit chemin boueux&#8221; complètement inutiles. </p>
<p>D&#8217;abord, si une meuf veut pas s&#8217;envoyer en l&#8217;air pendant ses règles, y a peu de chance qu&#8217;elle accepte la sodo. Ensuite, si vous ne voulez pas mettre votre bite devant quand ça saigne pour des pseudos raison d&#8217;hygiène, qu&#8217;est-ce que vous allez la carrer dans un trou un caca ?</p>
<p>La période des règles, c&#8217;est tip top. D&#8217;abord, elle peut pas tomber enceinte si on couche aux premiers jours des règles. Ensuite, c&#8217;est auto-lubrifié. Enfin, beaucoup de femmes sont particulièrement chaudes pendant la période des règles, don&#8217;t on s&#8217;amuse vachement.</p>
<p>Autant je ne recommande pas le cuni, autant on aurait tort de se priver d&#8217;une partie de jambe en l&#8217;air durant cette période. Pun intented.</p>
<p>Evidement laissez lui le temps de <a href="http://sametmax.com/le-travail-decriture-dans-le-domaine-du-cul/">tout retirer, y compris le tampax</a>.</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=7442&amp;md5=55688442bb8e73c8f26283e53bb2465d" title="Flattr" target="_blank"><img src="media/fc229d00.flattr-badge-large.png" data-original-source="http://sametmax.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>


feed_id: http://sametmax.com/?p=7423
title: Calcul décimaux avec norme IEEE 754/854 en Python
uri: Calcul-décimaux-avec-norme-IEEE-754-854-en-Python
url: http://sametmax.com/calcul-decimaux-avec-norme-ieee-754854-en-python/
content:
<p>Peut-on faire titre plus chiant que celui-là, je vous le demande ?</p>
<p>Toujours est-il que cet article n&#8217;interessera que des gens parfaitement chiants, à savoir des scientifiques tatillons, mais je sais qu&#8217;il y en a dans notre lectorat alors on va leur jeter un os.</p>
<p>Bref, vous savez que la division par zéro en Python, ça lève une exception :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">&gt;&gt;&gt;</span>  <span style="color: #ff4500;">1</span> / <span style="color: #ff4500;">0</span>
---------------------------------------------------------------------------
<span style="color: #008000;">ZeroDivisionError</span>                         Traceback <span style="color: black;">&#40;</span>most recent call last<span style="color: black;">&#41;</span>
<span style="color: #66cc66;">&lt;</span>ipython-input-<span style="color: #ff4500;">1</span>-b710d87c980c<span style="color: #66cc66;">&gt;</span> <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #66cc66;">&lt;</span>module<span style="color: #66cc66;">&gt;</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
----<span style="color: #66cc66;">&gt;</span> <span style="color: #ff4500;">1</span> <span style="color: #ff4500;">1</span> / <span style="color: #ff4500;">0</span>
&nbsp;
<span style="color: #008000;">ZeroDivisionError</span>: integer division <span style="color: #ff7700;font-weight:bold;">or</span> modulo by zero</pre></div></div>

<p>Certains esprits chagrins n&#8217;aiment pas ce comportement, et voudraient, par exemple, que cela retourne l&#8217;infini. Après tout, pourquoi pas.</p>
<p>N&#8217;y a-t-il rien qu&#8217;on puisse faire pour calmer la rétention anale qui se prépare à cette déconvenue ?</p>
<p>Bien sûr que si, on parle de Python voyons !</p>

<div class="wp_syntax"><div 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> <span style="color: #dc143c;">decimal</span> <span style="color: #ff7700;font-weight:bold;">import</span> setcontext,ExtendedContext, Decimal 
<span style="color: #66cc66;">&gt;&gt;&gt;</span> setcontext<span style="color: black;">&#40;</span>ExtendedContext<span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #ff4500;">1</span> / Decimal<span style="color: black;">&#40;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#41;</span>
Infinity
<span style="color: #66cc66;">&gt;&gt;&gt;</span> -<span style="color: #ff4500;">1</span> / Decimal<span style="color: black;">&#40;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#41;</span>
-Infinity</pre></div></div>

<p>Voilà. Si vous êtes une personne normale et manipulez des objets concrets comme des sous, des joujoux, des choux non additionnés avec des carottes ou des hashtags, les réglages par défaut sont parfaits. Mais si vous êtes un fan de scipy, traitant des matrices par bottes de douze, ça peut servir.</p>
<p>Spéciale dédicace à mes amis au CNRS. Bisoux partout !</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=7423&amp;md5=267e78ed8905332a2ea979aa760cf1a8" title="Flattr" target="_blank"><img src="media/fc229d00.flattr-badge-large.png" data-original-source="http://sametmax.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>


feed_id: http://sametmax.com/?p=7494
title: Minibelt, la petite soeur de batbelt
uri: Minibelt-la-petite-soeur-de-batbelt
url: http://sametmax.com/minibelt-la-petite-soeur-de-batbelt/
content:
<p>Quand j&#8217;ai créé batbelt, j&#8217;ai voulu en faire une boîte à outils pour des trucs pratiques qu&#8217;on ne trouve pas dans la lib standard, et qui n&#8217;ont pas de thèmes particuliers. Une genre de collection de snippets que j&#8217;utiliserais pour tous mes gros projets.</p>
<p>Mais voilà, il y a des choses qu&#8217;on utilise souvent, et d&#8217;autres moins. Et <a href="http://sametmax.com/mon-premier-projet-python3/">certaines personnes</a> ne veulent pas installer un package complet avec plusieurs modules juste pour quelques fonctions. Surtout que tous les projets ne sont pas des gros projets.</p>
<p>C&#8217;est pourquoi j&#8217;ai créé <a href="https://github.com/sametmax/minibelt">minibelt</a>.</p>
<p>C&#8217;est un subset de batbelt <strong>qui tient dans UN fichier</strong>, et qui contient uniquement les fonctions qu&#8217;on utilise le plus souvent. Vous pouvez bien sûr l&#8217;installer avec <a href="http://sametmax.com/votre-python-aime-les-pip/">pip</a>, mais le plus simple, c&#8217;est de juste copier / coller le fichier et le mettre à côté de votre code, puis de l&#8217;oublier.</p>
<p>L&#8217;autre bonne nouvelle, c&#8217;est que puisqu&#8217;il y a moins de code, je me suis bougé le cul pour rendre minibelt compatible Python 2 et Python 3 (enfin je crois :-)). Le README contient aussi l&#8217;ensemble de la documentation nécessaire.</p>
<p>Peut être même qu&#8217;un jour de pluie, j&#8217;ajouterai des tests unitaires, soyons fou.</p>
<p>Enjoy.</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=7494&amp;md5=8b8a1a57131bdddca3610c99d625b82a" title="Flattr" target="_blank"><img src="media/fc229d00.flattr-badge-large.png" data-original-source="http://sametmax.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>


feed_id: http://sametmax.com/?p=7501
title: Rapide test d&#8217;Ubuntu 13.10
uri: Rapide-test-d-Ubuntu-13-10
url: http://sametmax.com/rapide-test-dubuntu-13-10/
content:
<p>Ubuntu 13.10 vient de sortir et j&#8217;ai donc fait une micro partition pour le tester.</p>
<p>Installation sans histoire, un peu plus de config que d&#8217;hab car il faut virer toutes les merdes intrusives pour la vie privée (mais heureusement, y a des settings pour ça). Pas beaucoup de modifs, apparemment ils ont bossé la vitesse et la stabilité, ce qui est rare pour une non LTS. </p>
<p>Le résultat est qu&#8217;on a un OS qui est beaucoup plus stable que ce que Canonical avait l&#8217;habitude de donner les premiers jours de release. Et légèrement plus rapide.</p>
<p>En fait je suis tenté de migrer (mais pas con au point de le faire avant quelques mois), c&#8217;est globalement agréable à utiliser, épuré et fluide. On a pas encore Mir installé par défaut (OUF), donc ça reste un truc viable, qui tourne bien, avec des paquets plus récents à dispo. </p>
<p>Mon seul chagrin, c&#8217;est la nouveau Nautilus. La recherche est maintenant récursive par défaut, et impossible à changer. <del datetime="2013-10-22T13:07:50+00:00">En prime, plus d&#8217;extensions possibles, du coup &#8220;open terminal here&#8221; et &#8220;compare with meld&#8221; partent à la poubelle, et je les aimais beaucoup.</del></p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=7501&amp;md5=9cd758cab49143f3b4b32e4f2b81f3c5" title="Flattr" target="_blank"><img src="media/fc229d00.flattr-badge-large.png" data-original-source="http://sametmax.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>


feed_id: http://sametmax.com/?p=7507
title: Profiter du notebook de IPython
uri: Profiter-du-notebook-de-Ipython
url: http://sametmax.com/profiter-du-notebook-de-ipython/
content:
<p><a href="http://ipython.org">IPython</a> est un des outils qui me font trouver la programmation Python plus agréable que dans tous les autres langages : un shell avec <a href="http://sametmax.com/tag/ipython/">tellement d&#8217;astuces intégrées</a> que ça donne envie de vomir des arc-en-ciel.</p>
<p>Aujourd&#8217;hui je vais vous parler d&#8217;une fonctionnalité fantastique est très peu connue de IPython : <a href="http://ipython.org/notebook.html">le notebook</a>.</p>
<p>Si vous êtes scientifique ou manipulez pas mal de graphiques et de données numériques, <a href="http://www.randalolson.com/2012/05/12/a-short-demo-on-how-to-use-ipython-notebook-as-a-research-notebook/">c&#8217;est un must have</a>. Mais personnellement je trouve que c&#8217;est aussi un fantastique outil d&#8217;éducation, c&#8217;est génial pour les cours, les démos, et expérimenter avec du code inconnu.</p>
<p>Ça se présente sous la forme d&#8217;un shell IPython intégré dans une page Web, mais que l&#8217;on peut avoir sur son desktop, pas besoin d&#8217;avoir un serveur distant. Si vous avez un peu de temps, voici une vidéo de démo (avec un musique horrible) :</p>

<!-- iframe plugin v:2.3 - wordpress.org/extend/plugins/iframe/ -->
<iframe width="420" height="315" src="//www.youtube.com/embed/H6dLGQw9yFQ" frameborder="0" scrolling="no" class="iframe-class"></iframe>
<p>L&#8217;installation sous Ubuntu, c&#8217;est juste :</p>

<div class="wp_syntax"><div 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</span> <span style="color: #c20cb9; font-weight: bold;">install</span> ipython-notebook</pre></div></div>

<p>Pour Windows, il me semble, de mémoire, que c&#8217;est intégré dans l&#8217;exe. Pour Mac, je ne sais pas.</p>
<p>Et derrière il suffit de lancer la commande :</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">ipython notebook</pre></div></div>

<p>Et il va vous ouvrir votre navigateur avec un onglet sur votre notebook.</p>
<p>L’intérêt principal du notebook est que TOUT le code est coloré et est modifiable comme sur dans fichier mais TOUT le code est exécutable (et affiche son résultat juste après chaque ligne) comme dans un shell iPython, avec completion du code. Le meilleur des deux mondes quoi.</p>
<p>En prime on peut embeder du <a href="http://daringfireball.net/projects/markdown/syntax">markdown</a> (et donc des liens, des images, etc) dans le même notebook, sauvegarder ça pour plus tard, le partager, etc.</p>
<p>Personnellement, j&#8217;ai ceci dans mon .bashrc :</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">notebook <span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #7a0874; font-weight: bold;">&#41;</span> <span style="color: #7a0874; font-weight: bold;">&#123;</span>
    <span style="color: #007800;">processes</span>=$<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #c20cb9; font-weight: bold;">ps</span> aux <span style="color: #000000; font-weight: bold;">|</span> <span style="color: #c20cb9; font-weight: bold;">grep</span> <span style="color: #660033;">-i</span> <span style="color: #660033;">-P</span> <span style="color: #ff0000;">&quot;ipython notebook&quot;</span> <span style="color: #000000; font-weight: bold;">|</span> <span style="color: #c20cb9; font-weight: bold;">wc</span> -l<span style="color: #7a0874; font-weight: bold;">&#41;</span>
    <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #7a0874; font-weight: bold;">&#91;</span> <span style="color: #007800;">$processes</span> <span style="color: #660033;">-lt</span> <span style="color: #000000;">2</span> <span style="color: #7a0874; font-weight: bold;">&#93;</span><span style="color: #7a0874; font-weight: bold;">&#93;</span>
    <span style="color: #000000; font-weight: bold;">then</span>
        <span style="color: #7a0874; font-weight: bold;">pushd</span> <span style="color: #000000; font-weight: bold;">/</span>tmp
        <span style="color: #c20cb9; font-weight: bold;">nohup</span> ipython notebook <span style="color: #660033;">--port</span> <span style="color: #000000;">8889</span> <span style="color: #007800;">$1</span> <span style="color: #000000; font-weight: bold;">&amp;</span>
        <span style="color: #7a0874; font-weight: bold;">popd</span>
    <span style="color: #000000; font-weight: bold;">else</span>
        firefox http:<span style="color: #000000; font-weight: bold;">//</span>127.0.0.1:<span style="color: #000000;">8889</span>
    <span style="color: #000000; font-weight: bold;">fi</span>
<span style="color: #7a0874; font-weight: bold;">&#125;</span></pre></div></div>

<p>Comme ça en une commande je lance le serveur du notebook sur le port que je veux si il ne tourne pas, et si il tourne, j&#8217;ouvre firefox et ouvre un onglet dessus.</p>
<p>Quelques autres options très utiles :</p>
<p><strong>&#8211;pylab </strong>: Charger plein de libs pour transformer IPython en un matlab killer.<br />
<strong>&#8211;gui=lib </strong> : permet d&#8217;intégrer l&#8217;event loop de QT, wx, gtk, etc.<br />
<strong>&#8211;ip=0.0.0.0</strong> : si on veut que d&#8217;autres puisse accéder à notre notebook.</p>
<p>Il existe un <a href="http://nbviewer.ipython.org/">espèce de pastebin</a> spécialement fait pour le notebook, qui permet de partager ses expérimentations.</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=7507&amp;md5=e3d5a0aacc62ee0e8ac80d4d60319d9e" title="Flattr" target="_blank"><img src="media/fc229d00.flattr-badge-large.png" data-original-source="http://sametmax.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>


feed_id: http://sametmax.com/?p=7499
title: Installer SSH Plus sur Ubuntu
uri: Installer-SSH-Plus-sur-Ubuntu
url: http://sametmax.com/installer-ssh-plus-sur-ubuntu/
content:
<p><a href="http://sametmax.com/mon-environnement-de-travail/">Je vous avais parlé</a> de <a href="http://www.gulecha.org/2011/07/29/sshplus-a-sshmenu-compatible-appindicator/">SSH Plus</a>, mais sans mentionner son process d&#8217;install, un peu chiant.</p>
<p>Pour rappel, c&#8217;est un petit indicateur qui vous permet de lancer une commande arbitraire. Son usage principal est d&#8217;ouvrir un terminal qui se connecte immédiatement en SSH à un serveur distant, mais on peut y mettre n&#8217;importe quoi.</p>
<p>Pour l&#8217;installer :</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #666666; font-style: italic;"># on installe les dépendances</span>
<span style="color: #c20cb9; font-weight: bold;">sudo</span> <span style="color: #c20cb9; font-weight: bold;">apt-get</span> <span style="color: #c20cb9; font-weight: bold;">install</span> python-appindicator
<span style="color: #666666; font-style: italic;"># on se calle dans le dossier temporaire</span>
<span style="color: #7a0874; font-weight: bold;">cd</span> <span style="color: #000000; font-weight: bold;">/</span>tmp
<span style="color: #666666; font-style: italic;"># on download le script en Python</span>
<span style="color: #c20cb9; font-weight: bold;">wget</span> https:<span style="color: #000000; font-weight: bold;">//</span>raw.github.com<span style="color: #000000; font-weight: bold;">/</span>anilgulecha<span style="color: #000000; font-weight: bold;">/</span>misc<span style="color: #000000; font-weight: bold;">/</span>master<span style="color: #000000; font-weight: bold;">/</span>sshplus.py
<span style="color: #666666; font-style: italic;"># on le copie dans le dossier des exécutables</span>
<span style="color: #c20cb9; font-weight: bold;">sudo</span> <span style="color: #c20cb9; font-weight: bold;">mv</span> sshplus.py <span style="color: #000000; font-weight: bold;">/</span>usr<span style="color: #000000; font-weight: bold;">/</span>bin<span style="color: #000000; font-weight: bold;">/</span>sshplus
<span style="color: #666666; font-style: italic;"># on le rend exécutable</span>
<span style="color: #c20cb9; font-weight: bold;">sudo</span> <span style="color: #c20cb9; font-weight: bold;">chmod</span> +x <span style="color: #000000; font-weight: bold;">/</span>usr<span style="color: #000000; font-weight: bold;">/</span>bin<span style="color: #000000; font-weight: bold;">/</span>sshplus</pre></div></div>

<p>Pour le lancer, il n&#8217;y a plus qu&#8217;à faire :</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">sshplus</pre></div></div>

<p>Dans un terminal.</p>
<p>Moi, je le rajoute dans ma liste des programme automatiquement lancé au démarrage, comme ça je n&#8217;y pense plus (&#8220;Dash&#8221; > &#8220;Applications au démarrage&#8221;).</p>
<p>Après, vous pouvez lui faire lancer les commandes que vous voulez, en les mettant dans le fichier de config (~/.sshplus) en suivant la syntaxe  </p>
<pre>Nom à afficher|commande|options</pre>
<p>Par exemple :</p>
<pre>Server Prod 12|guake|-t -n "new" -e "ssh username@adresse_ip"
</pre>
<p>Ceci va rajouter une entrée dans le menu nommée &#8220;Server Prod 12&#8243;. Si on clique dessus, ça lance <code>guake -t -n "new" -e "ssh username@adresse_ip"</code>, ce qui m&#8217;ouvre un nouvel onglet dans mon terminal guake avec lance la commande <code>ssh username@adresse_ip</code> juste après.</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=7499&amp;md5=41cedb422864ba4c710122ece621c37b" title="Flattr" target="_blank"><img src="media/fc229d00.flattr-badge-large.png" data-original-source="http://sametmax.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>


feed_id: http://sametmax.com/?p=7525
title: Afficher l&#8217;IP d&#8217;un visiteur &#8211; Django vs Nginx
uri: Afficher-la-vraie-IP-d-un-visiteur-Django-vs-Nginx
url: http://sametmax.com/afficher-la-vrai-ip-dun-visiteur-django-vs-nginx/
content:
<p>Lorsque l&#8217;on veut connaitre son ip on fait souvent appel à des sites du genre: <a href="http://www.whatismyip.com/">whatismyip.com</a>, <a href="http://www.mon-ip.com/">mon-ip.com</a> ou on utilise un ifconfig en ssh.<br />
Des fois on a aussi besoin de connaître l&#8217;ip d&#8217;un visiteur sur son site, 2 petites méthodes pour le faire sous Django et Nginx.</p>
<p><strong>Sous Django:</strong> </p>
<p>Dans l&#8217;<a href="https://docs.djangoproject.com/en/dev/topics/http/urls/">Urlconf</a></p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">urlpatterns = patterns<span style="color: black;">&#40;</span><span style="color: #483d8b;">''</span>,
    <span style="color: #808080; font-style: italic;"># return client IP</span>
    url<span style="color: black;">&#40;</span>r<span style="color: #483d8b;">'^my_ip$'</span>, get_ip<span style="color: black;">&#41;</span>,
<span style="color: black;">&#41;</span></pre></div></div>

<p>Créez une <a href="https://docs.djangoproject.com/en/dev/topics/http/views/">vue</a> du nom de get_ip qui sera utilisée par l&#8217;urlconf</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">from</span> django <span style="color: #ff7700;font-weight:bold;">import</span> http
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> get_ip<span style="color: black;">&#40;</span>request<span style="color: black;">&#41;</span>:
    <span style="color: #483d8b;">&quot;&quot;&quot;
        Vue qui retourne l'IP du client
    &quot;&quot;&quot;</span>
    <span style="color: #ff7700;font-weight:bold;">try</span>:
&nbsp;
    	<span style="color: #808080; font-style: italic;"># récupère l'ip du client</span>
        <span style="color: #ff7700;font-weight:bold;">return</span> http.<span style="color: black;">HttpResponse</span><span style="color: black;">&#40;</span>request.<span style="color: black;">META</span><span style="color: black;">&#91;</span><span style="color: #483d8b;">&quot;REMOTE_ADDR&quot;</span><span style="color: black;">&#93;</span> <span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">except</span> <span style="color: #008000;">Exception</span>, e:
        <span style="color: #ff7700;font-weight:bold;">return</span> http.<span style="color: black;">HttpResponse</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'error %s'</span> <span style="color: #66cc66;">%</span> e<span style="color: black;">&#41;</span></pre></div></div>

<p>Le code ci-dessus peut retourner l&#8217;adresse locale (127.0.0.1) dans ce cas il faut tester l&#8217;existence de la variable <strong>HTTP_X_REAL_IP</strong>, certains serveurs web ont besoin d&#8217;être <a href="http://rtcamp.com/tutorials/nginx/forwarding-visitors-real-ip/">configuré</a>. </p>
<p><strong>Sous Nginx:</strong></p>
<p>Dans le fichier de configuration de nginx on écrit une nouvelle <a href="http://wiki.nginx.org/HttpCoreModule#location">location</a></p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #808080; font-style: italic;"># return client ip</span>
location /my_ip <span style="color: black;">&#123;</span>
    default_type <span style="color: #483d8b;">'text/plain'</span><span style="color: #66cc66;">;</span>
    content_by_lua <span style="color: #483d8b;">'ngx.print(ngx.var.remote_addr)'</span><span style="color: #66cc66;">;</span>
<span style="color: black;">&#125;</span></pre></div></div>

<p>il suffit de se rendre à l&#8217;url http://monsite.com/my_ip pour voir s&#8217;afficher son ip. Cependant il faut avoir nginx compilé avec le module <a href="http://wiki.nginx.org/HttpLuaModule">Lua</a> ce qui peut être délicat si l&#8217;on a jamais compilé d&#8217;application.</p>
<p><strong><br />
Conclusion:</strong></p>
<p>Si l&#8217;on s&#8217;en réfère aux deux exemples ci dessus on serait tenté d&#8217;utiliser Nginx car en une seule ligne tout le bazar est réglé.<br />
Le hic c&#8217;est qu&#8217;il faut que Nginx soit compilé avec le module Lua pour afficher l&#8217;ip (sauf si quelqu&#8217;un connaît une autre façon d&#8217;afficher un message de sortie).<br />
La version Django n&#8217;est pas fiable à 100% car suivant comment est configuré votre serveur web il se peut que vous vous retrouviez avec une ip du genre 127.0.0.1.<br />
Il y a aussi la possibilité de parser le résultat des sites web cités en tout début d&#8217;article, certains proposent des Api je crois mais vous dépendez d&#8217;un autre service (on faisait ça au début) qui peuvent vous lâcher à tout moment (ce qui nous est arrivé).<br />
Personnellement je compile toujours nginx avec Lua et quelques autres modules, ça permet de s&#8217;affranchir de plus en plus du backend.</p>
<p>PS: j&#8217;ai mis à jour le titre car il laissait sous-entendre autre chose (merci à Sébastien)</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=7525&amp;md5=5db442cb353a28e02057726c4e826969" title="Flattr" target="_blank"><img src="media/fc229d00.flattr-badge-large.png" data-original-source="http://sametmax.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>


feed_id: http://sametmax.com/?p=7541
title: WARNING: File not found. Did you forget to save?
uri: WARNING-File-not-found-Did-you-forget-to-save
url: http://sametmax.com/warning-file-not-found-did-you-forget-to-save/
content:
<p>Un lecteur nous a <a href="http://sametmax.com/profiter-du-notebook-de-ipython/#comment-15166">rapporté ce problème</a> quand il utilisait la commande magique <code>%edit</code> dans IPython avec Sublime Text.</p>
<p>Magie d&#8217;internet, un autre lecteur lui a répondu en comment, mais je me dis que donner un peu de visibilité à la réponse peut pas faire de mal, vu que je n&#8217;ai pas trouvé facilement la solution via <del datetime="2013-10-25T12:40:42+00:00">Google</del> DuckDuckGo.</p>
<p>L&#8217;idée est tout simplement d&#8217;utiliser l&#8217;option <code>-w</code> dans la ligne de commande pour appeler l&#8217;éditeur. En effet, sans cela l&#8217;appel à ST est non bloquant, et IPython perd la référence au processus sans avoir de valeur de retour.</p>
<p>Par exemple, dans votre <em>ipython_config.py</em> :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">c.<span style="color: black;">TerminalInteractiveShell</span>.<span style="color: black;">editor</span> = <span style="color: #483d8b;">&quot;sublime_text -w&quot;</span></pre></div></div>

 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=7541&amp;md5=efc6c9f7dc228a171ec901c5c3d892ef" title="Flattr" target="_blank"><img src="media/fc229d00.flattr-badge-large.png" data-original-source="http://sametmax.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>


feed_id: http://sametmax.com/?p=7549
title: Évitez A TOUT PRIX le site airbnb
uri: Évitez-A-TOUT-PRIX-le-site-airbnb
url: http://sametmax.com/evitez-a-tout-prix-le-site-airbnb/
content:
<p>On m&#8217;avait dit beaucoup de bien de ce site, qui permet de trouver des logements pas chers chez l&#8217;habitant dans tous les pays du monde.</p>
<p>Effectivement, c&#8217;est bien foutu, c&#8217;est propre et lisible, et il y a du choix. Alors, partant quelques jours avec une copine en voyage, je me suis dis que ça se tentait.</p>
<p>A l&#8217;inscription, à la réservation, un long form à remplir, avec la carte à rentrer, la caution de 70 euros dans les dents, les frais que prend airbnb qui se rajoutent en dernière minute à la facture, etc. Bon, c&#8217;est du classique, pas de quoi en faire un fromage.</p>
<p>Là où ça se corse, c&#8217;est qu&#8217;APRES tout ce merdier habituel, je reçois une notification me signalant que <strong>ma réservation n&#8217;était pas envoyée.</strong></p>
<p>WHAT ?</p>
<p>Et non ! Il faut maintenant passer par un stade de &#8220;vérification&#8221;, pour votre sécurité, messieurs-dames.</p>
<p>A chaque fois que je lis &#8220;pour votre sécurité&#8221; (sur les panneaux signalant les caméras, les radars, sur les formulaires, sur les contrats, etc), j&#8217;ai des envies de meurtre. Je voudrais trouver le mec qui a écrit ces lignes et lui faire bouffer sa connerie pour voir si elle a un goût de sécurité.</p>
<p>D’abord, uploader un document d&#8217;identité.</p>
<p>Arg.</p>
<p>Bon, admettons, le mec va t’accueillir chez lui, tout ça, ils veulent rassurer le chaland. Ça fait grincer les dents du voyageur que je suis ce lissage des pratiques, mais je me soumet à l&#8217;exercice. C&#8217;est comme ça qu&#8217;on appâte le main stream et qu&#8217;on a plus de choix, moins cher.</p>
<p>Next page, demande de photo de profile obligatoire, publique.</p>
<p>Mais fuck !</p>
<p>J&#8217;ai pas envie que mon nom, mon prénom (qu&#8217;ils m&#8217;ont demandé, et affichent sans me prévenir dans mon profile) et ma photo soient sur le net, bordel.</p>
<p>Je mets un avatar de merde en espérant que les modos le voient pas.</p>
<p>Mais attention, il y a encore deux étapes !!!</p>
<p>Étape 3, pour des raisons de sécurité de mes couilles, il faut lier un compte en ligne. Mais tu te fous de ma gueule ???</p>
<p>Je lies un compte de test qui me sert à rien, un compte gmail de spam. Ils demandent évidement la permission de gérer mes contacts, parce que bien sûr, c&#8217;est indispensable&#8230; Toujours effectuer une sodomie après un prélèvement sanguin. C&#8217;est pour votre sécurité.</p>
<p>Et pour finir, faire une vidéo de 10 secondes avec ma cam, me présentant.</p>
<p>VAS TE FAIRE FOUTRE !</p>
<p>(en plus leur applet flash ne marche sous aucun nav sous Linux)</p>
<p>La seule bonne nouvelle, c&#8217;est que la fonction &#8220;supprimer le compte&#8221; est facile à trouver.</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=7549&amp;md5=b190ff94f4b320efb9b76c27cf48fbfe" title="Flattr" target="_blank"><img src="media/fc229d00.flattr-badge-large.png" data-original-source="http://sametmax.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>


feed_id: http://sametmax.com/?p=7557
title: Encore une pause
uri: Encore-une-pause
url: http://sametmax.com/encore-une-pause/
content:
<p>En ce moment c&#8217;est de la publication en pointillés, pas mal de déplacement, etc.</p>
<p>Bref, tout ça pour dire qu&#8217;on se retrouve le 5 ou le 6. Là, je me casse.</p>
<p>Mais Max m&#8217;a parlé d&#8217;un petit article sympa&#8230;</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=7557&amp;md5=81acd127e138b3c3905027f4c18b36cc" title="Flattr" target="_blank"><img src="media/fc229d00.flattr-badge-large.png" data-original-source="http://sametmax.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>


feed_id: http://sametmax.com/?p=7563
title: Test de la JAMBOX de JAWBONE &#8211; Petit mais costaud !
uri: Test-de-la-JAMBOX-de-JAWBONE-Petit-mais-costaud
url: http://sametmax.com/test-de-la-jambox-de-jawbone-petit-mais-costaud/
content:
<p>Je suis quelqu&#8217;un qui voyage pas mal &#8211; pour ceux qui ont suivi le blog je suis actuellement à l&#8217;étranger (à l&#8217;hotel) et je suis amené à me déplacer dans divers pays &#8211; et j&#8217;aime avoir un fond sonore quand je code, quand je ramène une petite aussi, quand je me détends, quand je regarde un bon Ghostbusters, bref un peu tout le temps.</p>
<p>Les ordis portables valent pas grand chose en son, de ce que j&#8217;ai pu entendre ça manque de basses à mon goût, de profondeur dans les mediums, c&#8217;est plutot nasillard.<br />
Mon petit Mac Book Air toussote dès que je pousse un peu le son sur de la musique rock pour aller danser le Jerk, celui de Sam fait pas mieux et j&#8217;ai pas envie de me balader avec une chaine Hifi quand je veux mettre un peu de son à l&#8217;heure du Ricard.</p>
<p>Il y a de cela quelques mois Sam a acheté une JAMBOX de chez <a href="https://jawbone.com/speakers/jambox">Jawbone</a>, une petite boite rouge toute laide qui ressemble à une brique. Très septique et prêt à lui lancer une de mes fameuses phrases Coféenne &#8220;c&#8217;est de la merde&#8221; je suis resté asser surpris lorsque la petite brique s&#8217;est mise en action.</p>
<p>Avec les semaines l&#8217;idée de m&#8217;en procurer une me turlupina jusqu&#8217;à ce que je la trouve dans un &#8220;apple store&#8221; local pour seulement 95€ (140€ chez Amazon France, c&#8217;était une promo). J&#8217;ai sauté sur l&#8217;occas et je dois dire que je ne suis pas déçu du résultat. C&#8217;est parti pour un ptit test !</p>
<p><strong>Le tout en musique!</strong><br />
<iframe width="560" height="315" src="//www.youtube.com/embed/kkLTxsAhURw" frameborder="0" allowfullscreen></iframe></p>
<p><strong> Ouverturage de la boite:</strong></p>
<div id="attachment_7565" class="wp-caption aligncenter" style="width: 660px"><img src="media/c1fe3c1e.unbox.jpg" data-original-source="http://sametmax.com/wp-content/uploads/2013/10/unbox.jpg" alt="" title="Jambox unboxed - aux côtés de notre étalon maison" width="650" height="462" class="size-full wp-image-7565" /><p class="wp-caption-text">Jambox unboxed - aux côtés de notre étalon maison</p></div>
<p>L&#8217;ensemble se compose de la jambox, d&#8217;un cordon mini jack et d&#8217;une alimentation bien foutue avec cordon usb/micro usb. Un peu trop d&#8217;emballage à mon goût mais c&#8217;est la mode à la &#8220;Aiepeulle&#8221;.<br />
J&#8217;ai pris soin d&#8217;y joindre un objet très courant afin de vous donner une idée de la taille. </p>
<div id="attachment_7569" class="wp-caption aligncenter" style="width: 660px"><img src="media/41b58c73.side.jpg" data-original-source="http://sametmax.com/wp-content/uploads/2013/10/side.jpg" alt="" title="Jambox de profil" width="650" height="577" class="size-full wp-image-7569" /><p class="wp-caption-text">Bouton on/off, mini jack pour y brancher son smartphone old school ainsi que la prise micro usb de recharge</p></div>
<div id="attachment_7575" class="wp-caption aligncenter" style="width: 660px"><img src="media/0635f9f8.top_button.jpg" data-original-source="http://sametmax.com/wp-content/uploads/2013/10/top_button.jpg" alt="" title="Tu me dis de le faire moins fort, je le fait moins fort..." width="650" height="492" class="size-full wp-image-7575" /><p class="wp-caption-text">Pratique les gros boutons de volume pour quand on est cuit...</p></div>
<p>Sur le côté on a 3 boutons, le bouton on/off et pairing pour la connexion bluetooth, un mini jack pour y brancher un casque, la prise micro usb pour recharger la bête. Sur le dessus le volume avec de gros boutons pour pas se louper quand on est cuit lors de l&#8217;apéro.<br />
La Jambox pèse quelques 300 grammes, pas très lourd au final pour le son qui en sort. Pour ce qui est de l&#8217;autonomie j&#8217;ai pu regarder un film sans problème et elle est donnée pour 10h (ce que je doute quand même, ça reste à tester)</p>
<div id="attachment_7571" class="wp-caption aligncenter" style="width: 660px"><img src="media/9cf44994.plug_telescopic.jpg" data-original-source="http://sametmax.com/wp-content/uploads/2013/10/plug_telescopic.jpg" alt="" title="Prise rabatable" width="650" height="867" class="size-full wp-image-7571" /><p class="wp-caption-text">Prise rabatable, pratique pour quand on voyage avec sortie USB</p></div>
<p>Le chargeur est pas mal car sa prise est rabatable, ceux qui voyages apprécieront, de l&#8217;autre côté c&#8217;est une sortie USB sur laquelle le cordon d&#8217;alimentation USB/Micro USB se branche, là aussi c&#8217;est pas mal si on le casse on rachète juste le cordon.</p>
<p><strong>Branchagationnement:</strong></p>
<p>La Jambox peut se brancher soit par la prise mini jack soit par Bluetooth, pour le Bluetooth il suffit de jumeler les deux appareils en suivant la notice :p<br />
Attention! Sous Mac il se peut que le son grésille, j&#8217;ai eu ce problème et il faut modifier un fichier de config:</p>
<p>SOUS MAC<br />
Il faut changer le bitrate de la connexion Bluetooth. Dans un terminal:</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">defaults <span style="color: #c20cb9; font-weight: bold;">write</span> com.apple.BluetoothAudioAgent <span style="color: #ff0000;">&quot;Apple Bitpool Min (editable)&quot;</span> <span style="color: #660033;">-integer</span> <span style="color: #000000;">48</span></pre></div></div>

<p>Redémarrez l&#8217;ordi, éteignez la lumière du salon, fermez le frigo, plantez un avocat pas trop mûr dans un bol à choucroute. Le problème devrait être résolu (en tous cas &#8220;chez moi ça marche&#8221;)</p>
<p><strong>Test en conditions sismiques:</strong></p>
<div id="attachment_7572" class="wp-caption aligncenter" style="width: 660px"><img src="media/550530e0.jambox_ass.jpg" data-original-source="http://sametmax.com/wp-content/uploads/2013/10/jambox_ass.jpg" alt="" title="Houuuuu attention à la chute!" width="650" height="493" class="size-full wp-image-7572" /><p class="wp-caption-text">Parfaite tenue de route dans les mediums et les basses ! ça craque les Watts!</p></div>
<div id="attachment_7573" class="wp-caption aligncenter" style="width: 660px"><img src="media/28864f28.jambox_ass2.jpg" data-original-source="http://sametmax.com/wp-content/uploads/2013/10/jambox_ass2.jpg" alt="" title="Regardes plus haut..." width="650" height="867" class="size-full wp-image-7573" /><p class="wp-caption-text">La pureté du son n&#039;a d&#039;égal que celle des lignes. Pointu, précis !</p></div>
<p>Une fois la bestiole connectée je lui ai imposé quelques tests sismo-sismiques qu&#8217;elle a remportée haut la main comme vous pouvez le constater sur ces photos.<br />
La première chose qui m&#8217;a surpris c&#8217;est les basses ! Profondes et moelleuses, à la fois dures et vigoureuses, non y a pas à dire ça vous rendrait un curé hétéro. Moi qui aime bien la deep house et la musique electro en général, je suis resté bluffé, j&#8217;ai testé aussi un peu de &#8220;<a href="http://www.youtube.com/watch?v=DRVvFYppU0w">classique</a>&#8220;, du <a href="http://www.youtube.com/watch?v=E49Z2L3yAZE">rock chrétien</a>, du <a href="http://www.youtube.com/watch?v=oXRjJdsljIQ">hallal</a>, ça pète bien.</p>
<p><strong>Conclusions:</strong><br />
Un pote est venu un soir et s&#8217;est connecté via son smartphone à la Jambox pour lancer sa playlist, c&#8217;était plutôt sympa car rapide sans se prendre la tête à trouver un câble, etc. C&#8217;est le côté cool du Bluettoth.<br />
Pour le moment je ne vois pas de bémol, même le prix est raisonnable (compter 150€ neuf) et le son est très bon, la bestiole se transporte partout (plage, hotels, pique-nique, etc) et l&#8217;autonomie est (sur le papier) très acceptable.</p>
<p>Aller une dernière&#8230;</p>
<div id="attachment_7580" class="wp-caption aligncenter" style="width: 310px"><img src="media/b16df295.jambxo_standup1.jpg" data-original-source="http://sametmax.com/wp-content/uploads/2013/10/jambxo_standup1.jpg" alt="" title="C&#039;est pas un Layboy" width="300" height="969" class="size-full wp-image-7580" /><p class="wp-caption-text">la pureté des lignes...</p></div>
<p>A vous cognac Jay!</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=7563&amp;md5=5f976825ac135949cfdf350111964767" title="Flattr" target="_blank"><img src="media/fc229d00.flattr-badge-large.png" data-original-source="http://sametmax.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>


feed_id: http://sametmax.com/?p=7602
title: Les annotations en Python 3
uri: Les-annotations-en-Python-3
url: http://sametmax.com/les-annotations-en-python-3/
content:
<p>Mais oui, on va parler un peu plus de Python 3 à partir de maintenant \o/</p>
<p>C&#8217;est qu&#8217;avec la prochaine version 3.4 qui <a href="http://docs.python.org/3.4/whatsnew/3.4.html">apporte tellement de bonnes choses</a>, <a href="https://docs.djangoproject.com/en/dev/releases/1.6/">Django 1.6</a>  pleinement compatible et des libs comme <a href="http://pillow.readthedocs.org/en/latest/">Pillow</a> et <a href="https://pypi.python.org/pypi/six/1.1.0">six</a> pour combler les trous, ça y est, on peut enfin s&#8217;y mettre.</p>
<p>Commençons donc par les <a href="http://www.python.org/dev/peps/pep-3107/">annotations</a>, feature simple, et qu&#8217;on ne retrouve pas backportée en 2.7.</p>
<h2>D&#8217;abord, à quoi servent les annotations ?</h2>
<p>A rien !</p>
<p>Non, non, je ne déconne pas. Non seulement les annotations sont parfaitement optionnelles, mais en plus elles n&#8217;ont aucun effet.</p>
<p>Je répète pour que ça rentre : vous n&#8217;avez pas à utiliser les annotations. Aucun programme Python n&#8217;a besoin d&#8217;utiliser les annotations. Vous pouvez programmer votre vie entière en Python sans avoir jamais à utiliser les annotations. Et si vous les utilisez, elles ne changeront rien à votre programme.</p>
<p>Point.</p>
<h2>Non, mais sérieux, ça sert à quoi ?</h2>
<p>Python est un langage très souple, et une raison de sa souplesse c&#8217;est que la nature des données que vous traitez est dynamiquement découverte à l’exécution. Particulièrement, le type des variables est dynamique. La portée des variable est dynamique.</p>
<p>Avantages :</p>
<ul>
<li>Le code est court et clair.</li>
<li>Le langage est très facile à apprendre.</li>
<li>On peut utiliser le duck typing.</li>
</ul>
<p>Inconvénients :</p>
<ul>
<li>Il faut écrire des informations en plus dans la doc.</li>
<li>Le code est plus lent car la VM ne peut optimiser le code pour les types.</li>
<li>Les IDE ont moins d&#8217;outils pour aider à la rédaction du code.</li>
</ul>
<p>C&#8217;est la nature de Python. Pour certains cas, c&#8217;est ce qu&#8217;on veut. Dans d&#8217;autres cas où ce n&#8217;est pas adapté, il faut choisir un autre langage.</p>
<p>Les annotations sont là pour corriger ce point : on va permettre de fournir des informations en plus, <strong>si, et seulement, si, on le souhaite</strong>.</p>
<p>Ces informations n&#8217;auront aucun impact sur l&#8217;exécution du code. La VM Python va les ignorer. Mais un outil extérieur pourra potentiellement les utiliser pour en faire quelque chose.</p>
<h2>Show me the code !</h2>
<p>Faites chauffer votre interpréteur de Python 3&#8230;</p>
<p>On peut annoter <strong>uniquement</strong> les paramètres d&#8217;une fonction (ou méthode) :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #ff7700;font-weight:bold;">def</span> ma_fonction<span style="color: black;">&#40;</span>param1: <span style="color: #483d8b;">&quot;Une annotation&quot;</span>, param2: <span style="color: #ff4500;">1</span> + <span style="color: #ff4500;">1</span>, param3: <span style="color: #008000;">int</span><span style="color: black;">&#41;</span>:
...     <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span>param1, param2, param3<span style="color: black;">&#41;</span>
...
<span style="color: #66cc66;">&gt;&gt;&gt;</span> ma_fonction<span style="color: black;">&#40;</span><span style="color: #ff4500;">1</span>,<span style="color: #ff4500;">2</span>,<span style="color: #ff4500;">3</span><span style="color: black;">&#41;</span>  <span style="color: #808080; font-style: italic;"># une annotation ne change absolument RIEN</span>
<span style="color: #ff4500;">1</span> <span style="color: #ff4500;">2</span> <span style="color: #ff4500;">3</span></pre></div></div>

<p>L&#8217;annotation se note donc ainsi : nom du paramètre: annotation.</p>
<p>L&#8217;annotation PEUT être n&#8217;importe quelle expression Python valide. En fait l&#8217;annotation DOIT être une expression valide. Et <strong>cette expression sera exécutée</strong> une, et une seule fois, à l&#8217;initialisation du module. Le résultat sera stocké et accessible, via l&#8217;attribut <code>__annotations__</code> :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">&gt;&gt;&gt;</span> ma_fonction.__annotations__
<span style="color: black;">&#123;</span><span style="color: #483d8b;">'param1'</span>: <span style="color: #483d8b;">'Une annotation'</span>, <span style="color: #483d8b;">'param2'</span>: <span style="color: #ff4500;">2</span>, <span style="color: #483d8b;">'param3'</span>: <span style="color: #66cc66;">&lt;</span>class <span style="color: #483d8b;">'int'</span><span style="color: #66cc66;">&gt;</span><span style="color: black;">&#125;</span></pre></div></div>

<p>Évidément, les annotations se mélangent sans problème avec les cas avancés de paramétrage :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #ff7700;font-weight:bold;">def</span> ma_fonction<span style="color: black;">&#40;</span>param1 : <span style="color: #483d8b;">&quot;Une annotation&quot;</span> = <span style="color: #483d8b;">&quot;valeur par défaut&quot;</span>, <span style="color: #66cc66;">*</span>param2: <span style="color: #483d8b;">&quot;Autre annotation&quot;</span><span style="color: black;">&#41;</span>:
... <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span>param1, param2<span style="color: black;">&#41;</span>
...
<span style="color: #66cc66;">&gt;&gt;&gt;</span> ma_fonction<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
valeur par défaut <span style="color: black;">&#40;</span><span style="color: black;">&#41;</span></pre></div></div>

<p>On peut également spécifier une annotation pour la valeur de retour :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #ff7700;font-weight:bold;">def</span> ma_fonction<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span> -<span style="color: #66cc66;">&gt;</span> <span style="color: #008000;">None</span>: <span style="color: #808080; font-style: italic;"># un petit goût de coffeescript</span>
...     <span style="color: #ff7700;font-weight:bold;">pass</span>
...
<span style="color: #66cc66;">&gt;&gt;&gt;</span> ma_fonction.__annotations__
<span style="color: black;">&#123;</span><span style="color: #483d8b;">'return'</span>: <span style="color: #008000;">None</span><span style="color: black;">&#125;</span></pre></div></div>

<p>Et combiner tout ce bordel pour faire des trucs bien compliqués qui vous garantissent la sécurité d&#8217;emploi, ce qui manque cruellement en Python (les trucs compliqués, pas la sécurité d&#8217;emploi&#8230;):</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #ff7700;font-weight:bold;">def</span> ma_fonction<span style="color: black;">&#40;</span>param1: <span style="color: #ff7700;font-weight:bold;">lambda</span> x: x <span style="color: #66cc66;">*</span> <span style="color: #ff4500;">2</span>,
...                 <span style="color: black;">param2</span>: <span style="color: black;">&#40;</span><span style="color: #ff7700;font-weight:bold;">lambda</span> x: x <span style="color: #66cc66;">*</span> <span style="color: #ff4500;">2</span><span style="color: black;">&#41;</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">2</span><span style="color: black;">&#41;</span> = <span style="color: #ff4500;">5</span>,
...                 <span style="color: #66cc66;">**</span>params : <span style="color: #483d8b;">&quot;Keywords parameters rocks&quot;</span><span style="color: black;">&#41;</span> -<span style="color: #66cc66;">&gt;</span> <span style="color: #008000;">list</span>:
...     <span style="color: black;">res</span> = <span style="color: black;">&#91;</span>param1, param2<span style="color: black;">&#93;</span>
...     <span style="color: black;">res</span>.<span style="color: black;">extend</span><span style="color: black;">&#40;</span>params<span style="color: black;">&#41;</span>
...     <span style="color: #ff7700;font-weight:bold;">return</span> res
...
<span style="color: #66cc66;">&gt;&gt;&gt;</span> ma_fonction<span style="color: black;">&#40;</span><span style="color: #ff4500;">1</span>, <span style="color: #ff4500;">2</span>, param3=<span style="color: #ff4500;">3</span>, param4=<span style="color: #ff4500;">4</span><span style="color: black;">&#41;</span>
<span style="color: black;">&#91;</span><span style="color: #ff4500;">1</span>, <span style="color: #ff4500;">2</span>, <span style="color: #483d8b;">'param4'</span>, <span style="color: #483d8b;">'param3'</span><span style="color: black;">&#93;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> ma_fonction.__annotations__
<span style="color: black;">&#123;</span><span style="color: #483d8b;">'return'</span>: <span style="color: #66cc66;">&lt;</span>class <span style="color: #483d8b;">'list'</span><span style="color: #66cc66;">&gt;</span>, <span style="color: #483d8b;">'param1'</span>: <span style="color: #66cc66;">&lt;</span>function <span style="color: #66cc66;">&lt;</span>lambda<span style="color: #66cc66;">&gt;</span> at 0x7f77a2982e60<span style="color: #66cc66;">&gt;</span>, <span style="color: #483d8b;">'param2'</span>: <span style="color: #ff4500;">4</span>, <span style="color: #483d8b;">'params'</span>: <span style="color: #483d8b;">'Keywords parameters rocks'</span><span style="color: black;">&#125;</span></pre></div></div>

<p>Les lambdas ne peuvent pas être annotées par contre.</p>
<h2>Le potentiel des annotations</h2>
<p>Les annotations sont le cas typique d&#8217;une fonctionnalité bac à sable. En clair, sur la mailling list il y a eu de nombreuses requêtes pour permettre de la vérification de type, de l&#8217;auto documentation, de la translittération et autres joyeusetés.</p>
<p>Ne sachant pas comment répondre de manière propre à ces demandes, ni lesquelles étaient les plus prioritaires, les annotations ont été créées. Le but et de laisser maintenant la communauté fabriquer les outils, et ainsi :</p>
<ul>
<li>Ceux pour les fonctionnalités les plus utilisées seront naturellement priorisées.</li>
<li>Les standards pour les annotations vont émerger par l&#8217;usage, et pas parce que Guido l&#8217;a décidé depuis son bureau au doigt mouillé.</li>
<li>Les fonctionnalités du genre &#8220;je veux un poney&#8221; seront tout simplement ignorées puisque personne ne travaillera suffisamment dessus (quand quelque chose est un caprice, le capricieux se sort rarement les extrémités manuelles de la cavité rectale.)</li>
</ul>
<p>Des outils comme <a href="http://www.fightingquaker.com/pyanno/">pyanno</a> donnaient déjà un exemple de ce que la communauté pouvait désirer. Reste à savoir si ce sera vraiment utilisé. Les gens qui font du Python sont rarement fan du Java. Mais le caractère optionnel de la chose pourrait bien ajouter un vrai plus au langage sans l&#8217;alourdir.</p>
<p>Voici donc ce qu&#8217;on peut attendre des outils tierces parties qui utiliseront les annotations dans le futur :</p>
<h3>Amélioration des performances</h3>
<p>L&#8217;utilisation de <a href="https://rpython.readthedocs.org/en/improve-docs/">RPython</a> pour coder <a href="http://pypy.org/">Pypy</a> a montré que les perfs de Python pouvaient être fantastiques, si on rajoutait quelques annotations. RPython, est, je le rappelle, un subset de Python (donc tout code RPython tourne dans l&#8217;interpréteur Python normal), mais avec des annotations de type, sous forme de commentaires.</p>
<p>On peut donc imaginer que dans le futur, les codes en fort besoin de perfs comme pour l&#8217;embarqué ou le traitement scientifique, pourront ajouter dans les parties clés de l&#8217;algo des annotations pour booster la vitesse ou diminuer la mémoire consommée. On parlerait ici alors d&#8217;annotation de type. <code>int</code>, <code>list</code>, <code>UneClasse</code> sont en effet des expressions Python valides&#8230;</p>
<p>L&#8217;avantage de l&#8217;annotation, c&#8217;est son caractère purement optionnel, qu&#8217;on peut ajouter seulement à certains codes, ou à une partie du code.</p>
<h3>Aide à la saisie</h3>
<p>Les IDE ont du mal avec Python. La complétion du code, l&#8217;aide en popup, la refactorisation automatique et toutes ces joyeusetés sont rarement bien implémentées.</p>
<p>Dans ma vie de tous les jours, je m&#8217;en branle. Je code tellement vite en Python, je ne m&#8217;en aperçois même pas. Mais quand j&#8217;utilise une nouvelle lib, ça peut être utile.</p>
<p>Typiquement, pour un code comme celui de <a href="https://github.com/sametmax/0bin/">0bin</a>, je ne me servirais pas des annotations. Mais pour une lib comme <a href="https://github.com/sametmax/minibelt">minibelt</a>, je prendrais peut être le temps de mettre des annotations de type, pour aider ceux qui vont l&#8217;utiliser. Ou une annotation pour signaler les exceptions que certaines fonctions peuvent lever.</p>
<h3>Génération de documentation</h3>
<p>Certains voient les annotations comme un complément aux docstrings. Ce n&#8217;est pas mon cas, mais je vous le note, au cas où ça devienne une tendance.</p>
<h3>Vérification de Type</h3>
<p>Dans la même lignée de l&#8217;aide à la saisie, pour certaines fonctions (c&#8217;est rare, mais ça arrive), on veut éviter le duck typing et forcer l&#8217;utilisateur à passer un type en particulier. Avoir cette possibilité via les annotations pourraient être utile.</p>
<p>Je suis septique sur cet usage, en effet des libs existent depuis des années pour faire cela, et plus, via des décorateurs, et ça n&#8217;est pas très utilisé. La différence est qu&#8217;un mécanisme standard pourra être détecté par les IDE.</p>
<p>Après on risque d&#8217;avoir des abus pour ce genre de fonctionnalités. Je vois d&#8217;ici arriver les codeurs d&#8217;autres langages caféinés, essayant de pousser l&#8217;usage d&#8217;une annotation rendant des attributs <code>private</code> :-)</p>
<p>Heureusement, les annotations seront normalement pour toujours optionnelles.</p>
<h3>Translittération de code</h3>
<p>Vous avez un code Python et vous voulez le transformer en code Cobol ? Bon, le compilateur de Pypy a déjà le potentiel de le faire, mais avec les annotations, il est potentiellement possible de rajouter suffisamment d&#8217;informations pour qu&#8217;on puisse toujours transformer un code de Python vers un autre langage Turing complet.</p>
<p>J&#8217;ai dit potentiellement.</p>
<h2>Je répète une dernière fois&#8230;</h2>
<p>Les annotations ne font rien. Elles n&#8217;ont pas le but de faire quelque chose et de toute façon sont optionnelles.</p>
<p>Leur but est de permettre à la communauté de créer des nouveaux outils utilisant les annotations et voir lesquels seront les plus utilisés, matures et désirés.</p>
<p>Pour le moment, il n&#8217;y a pas grand chose de fait avec, mais jusqu&#8217;ici Python 3 n&#8217;a pas été très populaire. Cela risque de changer avec 2014 qui propulsera Python 3.4 dans la cour des grands.</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=7602&amp;md5=07b3f32d4f8ec8a3a4e4363f39dbfc9b" title="Flattr" target="_blank"><img src="media/fc229d00.flattr-badge-large.png" data-original-source="http://sametmax.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>


feed_id: http://sametmax.com/?p=7621
title: La chute de la presse : internet en cause, vraiment ?
uri: La-chute-de-la-presse-internet-en-cause-vraiment
url: http://sametmax.com/la-chute-de-la-presse-quelles-causes/
content:
<p>Les gens qui lisent la presse d&#8217;information généraliste font partie de ceux qui ont le désir &#8211; à défaut d&#8217;y arriver effectivement &#8211; de faire un peu plus marcher leur cerveau que la moyenne.</p>
<p>Or, il est difficile de ne pas s&#8217;adonner à un triste bilan sur la dernière décennie de ses performances : <a href="http://www.dailykos.com/story/2011/11/25/1039957/-STUNNING-Comparing-U-S-World-Covers-for-TIME-Magazine">désinformation</a>, <a href="http://www.wat.tv/video/crise-euro-micro-trottoir-3zd6d_2idg5_.html">infantilisation du message</a>, <a href="http://www.lemonde.fr/idees/chat/2013/04/17/tour-d-horizon-de-l-actualite-coree-du-nord-terrorisme-defense_3161050_3232.html">sensationnalisme</a>, <a href="http://www.liberation.fr/monde/2013/10/27/destruction-des-armes-chimiques-la-syrie-dans-dans-les-delais_942672">manque d&#8217;analyse</a>, <a href="http://www.agoravox.fr/tribune-libre/article/quand-le-figaro-censure-des-75763">censure</a>, <a href="https://twitter.com/reymondin/status/311206675275198464">hypocrisie</a>, <a href="https://www.youtube.com/watch?v=tv53M1xcK0w">abus de marronniers et de sujets creux</a>, formes et formats éculés (alors que franchement, <a href="http://webdocu.fr/web-documentaire/2012/12/18/equipe-downi-explique-le-datajournalisme/">le renouveau est juste sous votre nez</a>), <a href="http://www.pearltrees.com/#/N-f=1_1760572&#038;N-fa=1092232&#038;N-p=12512785&#038;N-play=0&#038;N-s=1_1760572&#038;N-u=1_100951">relation évidente avec le pouvoir</a> (alors qu&#8217;on en attend un contre pouvoir, justement), et globalement, un manque de couilles évident, castrées par l&#8217;objectif financier.</p>
<p>Bref, la presse ne nous informe plus.</p>
<p>Et elle tombe des nues quand soudain, une source d&#8217;information neuve apparaît via internet, et que son public se barre.</p>
<p>Alors on crache sur les vilains pirates, ceux qui volent l&#8217;information et la publient ailleurs.</p>
<p>Le copier / coller est pourtant une pratique journalistique qui a atteint le statut de discipline Olympique.</p>
<p>Alors on crache sur les incompétents blogueurs qui ne sont que des amateurs ne vérifiant pas leurs sources.</p>
<p>La répétition aveugle d&#8217;une information non maîtrisée est pourtant un constat que tout spécialiste fait quotidiennement : vous le savez pour l&#8217;IT, mais j&#8217;ai discuté avec des avocats, des médecins, des agriculteurs&#8230; Tous sont effarés.</p>
<p>Alors on crache sur le modèle économique ! Comment ? Fournir une information gratuite ? Ça ne peut pas marcher ça, ma petite dame ! Nous on est sérieux ! Nous on bosse ! Nous on doit être payé !</p>
<p>Et pourtant, payé pour quoi ? Pour nous servir une information, au mieux réchauffée, mal digérée, composée d&#8217;ingrédients faisandés issus d&#8217;un producteur véreux dans une assiette sale ?</p>
<p>Je suis prêt à payer. <strong>Je paye des tas de choses sur le net.</strong> Vous n&#8217;avez pas remarqué comme tout le monde semble se faire un max de pognon sur Internet depuis les années 2000 ? Vous croyez qu&#8217;ils l&#8217;impriment ? Les gens paient. Surprise !</p>
<p>Je ne paie pas CETTE MERDE, c&#8217;est tout. À tous viser une ménagère de moins de 50 ans stéréotypée et sur-sollicitée, vous en avez perdu le cœur de votre revenu. </p>
<p>Les gens ne paient que ce qu&#8217;ils estiment avoir besoin d&#8217;acheter. Aussi étonnant que cela paraisse, ils ont un budget limité. Si, si. Et ils le dépense en entier. Parfois ils sont même à découvert. Étonnamment ça amène à prioriser.</p>
<p>Quand sur une échelle de valeur, &#8220;acheter un journal&#8221; est sous le barreau &#8220;obtenir des vies à Candy Crush&#8221;, on la ferme, et on se lance dans un peu d&#8217;introspection.</p>
<p>Si ça ne se vend pas, ce n&#8217;est pas parce que les gens sont de vils voleurs à l&#8217;esprit étroit. C&#8217;est parce qu&#8217;ils ne voient aucune raison de payer pour ça.</p>
<p>C&#8217;était pareil avec la musique en CD. Et Apple à tout raflé parce que les dinosaures n&#8217;ont pas compris comment faire de la thune sur le net et se sont mis à chialer au lieu de se bouger leurs gros culs bien engraissés par les ayant droit.</p>
<p>C&#8217;était pareil avec les films. Et Netflix a prouvé au monde que le piratage n&#8217;empêchait personne de faire des millions de bénéfice si on faisait ne serait-ce que mettre un peu de chantilly sur l&#8217;étron des produits habituels.</p>
<p>La presse ne nous a pas informé. Et en plus nous a emballé ça dans du papier toilette.</p>
<p>Personne n&#8217;achète un couteau qui ne coupe pas. Alors si en plus il est rouillé&#8230;</p>
<p>On est donc allé voir ailleurs.</p>
<p>Parce qu&#8217;on le pouvait, enfin.</p>
<p>Quand free est arrivé, le reste du marché s&#8217;est réveillé. On pouvait soudainement quitter le statu quo.</p>
<p>Avant la presse bénéficiait d&#8217;un marché captif où tous les acteurs s&#8217;étaient mis d&#8217;accord pour fournir des produits de la même médiocre qualité.</p>
<p>Et Internet est arrivé avec les blogueurs, les objecteurs de conscience, les journaux alternatifs, les wiki, les agrégateurs de news, les curateurs, les réseaux sociaux. Et une plate-forme sur laquelle le public pouvait répondre. S’exprimer. Juger. S’inscrire en faux. Les aborder, et les tutoyer. On pouvait soudainement quitter le statu quo.</p>
<p>Alors on l&#8217;a fait.</p>
<p>Un article comme celui-ci, vous ne le trouverez dans aucun journal. Or c&#8217;est exactement ce que je veux lire. Et devinez quoi ? Je n&#8217;ai pas été payé pour l&#8217;écrire. Et vous n&#8217;aurez pas à payer pour le lire. Il n&#8217;y a même pas de pub.</p>
<p>Si la presse veut de nouveau faire de l&#8217;argent, il va falloir qu&#8217;elle donne envie d&#8217;acheter. Il va falloir qu&#8217;elle fasse mieux que <a href="http://reflets.info">reflets</a>, <a href="http://sebsauvage.net">sebsauvage</a>, l&#8217;<a href="http://odieuxconnard.wordpress.com/">odieux connard</a>, <a href="http://www.maitre-eolas.fr">maitre eolas</a>, <a href="http://www.info-libre.fr/">info-libre</a> et l&#8217;ensemble des outils d&#8217;agrégation qui permettent de synthétiser, trier, filtrer et consulter exactement ce dont on a besoin, au meilleur moment.</p>
<p>Car clairement, je ne vais pas payer pour moins bien. Et actuellement, c&#8217;est exécrable.</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=7621&amp;md5=e9a964927c147042711d58e54ae88e0b" title="Flattr" target="_blank"><img src="media/fc229d00.flattr-badge-large.png" data-original-source="http://sametmax.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>


feed_id: http://sametmax.com/?p=7706
title: Parlez-nous de vous !
uri: Parlez-nous-de-vous
url: http://sametmax.com/parlez-nous-de-vous/
content:
<p>Depuis le temps qu&#8217;on pond des articles vous devez avoir cerné les personnages que sont Sam &#038; Max.<br />
Mais au fait nous on en sait pas beaucoup sur vous!<br />
ça serait sympa de nous raconter un peu votre vie, vos passions, vos fantasmes, ce qui vous passe par la tête.</p>
<p>Soyez pas timides, inutile de poster nom et prénom bien sur, mais en gros dans quelle région vous vous situez, votre jeunesse, pourquoi l&#8217;info et/ou la sodo, un bon ptit resto dans votre coin, ce qui vous fait bander, ce qui vous fait chier, bref votre vie quoi.</p>
<p><strong>Allez-y les cas soces, parlez-nous un peu de vous :)</strong></p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=7706&amp;md5=4429c1cb9377d57f865cb6d671b6a258" title="Flattr" target="_blank"><img src="media/fc229d00.flattr-badge-large.png" data-original-source="http://sametmax.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>


feed_id: http://sametmax.com/?p=7660
title: Apprendre le python en 10 ans&#8230;
uri: Apprendre-le-python-en-10-ans
url: http://sametmax.com/apprendre-le-python-en-10-ans/
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>Il y a quelques années, esseulé devant 1 millions de pixels noctures, j&#8217;ai tapé <em>&#8220;Comment devenir un hacker ?&#8221;</em> dans un monopolisant moteur de recherche&#8230;<br />
Comme ça&#8230;<br />
Pour déconner&#8230;</p>
<p>Je suis alors tombé sur le texte &#8220;<a href="media/3822024c.devenir_hacker.pdf" data-original-source="http://www.tice.ac-versailles.fr/logicielslibres/IMG/devenir_hacker.pdf">Comment devenir un hacker ?</a>&#8221; d&#8217;Eric Steven Raymond.</p>
<p>Après quelques instants dubitatifs où j&#8217;ai pris conscience que si j&#8217;avais écrit <em>&#8220;Comment planter des choux ?&#8221;</em> ou autres <em>&#8220;Comment dessiner un poulet en contre-plongée ?&#8221;</em> je serai certainement tombé sur un document du même nom, j&#8217;ai commencé à lire le texte en question.<br />
Mais ce n&#8217;est que plusieurs mois après que j&#8217;en suis venu à bout.</p>
<p>En effet, arrivé à la partie <em>&#8220;Apprenez à programmer&#8221;</em>, j&#8217;ai non seulement réalisé que je ne savais pas vraiment programmer mais surtout que je pouvais dès à présent mettre à l&#8217;épreuve ma théorie sur les choux et les poulets.<br />
J&#8217;ai donc cherché <em>&#8220;Comment apprendre à programmer ?&#8221;</em> et j&#8217;ai fini par tomber sur l&#8217;article &#8220;<a href="http://www.vizmatic.com/apprenez-a-programmer-en-dix-ans/lang/fr">Apprendre à programmer en 10 ans ?</a>&#8221;</p>
<p>Celui-là, je l&#8217;ai lu en entier et d&#8217;une seule traite.<br />
Mais le titre seulement avait suffit à me décomplexer pour deux ou trois vies.</p>
<h2>Comment acquérir une compétence en 10 ans?</h2>
<p>Quelle évidence !<br />
Tout me paraissait bien plus envisageable en me donnant 10 ans pour y arriver&#8230;<br />
Je veux apprendre l&#8217;espagnol ? Et bien je ferai le bilan dans 10 ans&#8230;<br />
Pas besoin de culpabiliser parce que je n&#8217;ai pas fait la page du jour de la méthode à Mimile&#8230;</p>
<p>Il devait être 1h du matin et je me suis dit :<br />
<em>&#8220;Et si j&#8217;apprenais le Python&#8230;&#8221;</em><br />
J&#8217;avais 10 ans devant moi, mais ce n&#8217;était pas une raison pour perdre du temps.</p>
<p>À 6h, j&#8217;avais donc bouclé la première partie du tuto &#8220;<a href="http://www.siteduzero.com/tutoriel-3-223267-apprendre-python.html">Apprendre le Python</a>&#8221; du site du zéro et entamé la seconde&#8230;</p>
<p>Maintenant, vous vous demandez peut-être, si, trois an plus tard, je connais le Python&#8230;<br />
Et bien je vous dirais ça dans sept ans&#8230; :-)</p>
<h2>Hello world !</h2>
<p>En attendant, j&#8217;ai proposé à Sam et Max de poster quelques articles de temps en temps&#8230;<br />
Je ne suis pas du tout developpeur, mais je n&#8217;ai aucun scrupule à écrire des lignes de code&#8230; encore moins à publier ma prose de cochon&#8230;</p>
<p>Sachant qu&#8217;il est tout à fait possible d&#8217;obtenir des résultats enthousiasmants avec du code bancal, je me propose donc de décomplexer les débutants en publiant des articles de mauvais élève&#8230;<br />
Nulle doute que les lecteurs avertis de S&#038;M sauront, par leurs commentaires avisés, réhausser le niveau technique de mes posts afin de les rendre aussi instructifs que ceux déjà disponibles sur ce blog&#8230;</p>
<p>À bientôt&#8230;</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=7660&amp;md5=9c30d5e7fe68b9db86cf98f5cecc9980" title="Flattr" target="_blank"><img src="media/fc229d00.flattr-badge-large.png" data-original-source="http://sametmax.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>


feed_id: http://sametmax.com/?p=7716
title: Mise à jour de Django-quicky pour supporter django 1.6
uri: Mise-à-jour-de-Django-quicky-pour-supporter-django-1-6
url: http://sametmax.com/mise-a-jour-de-django-quicky-pour-supporter-django-1-6/
content:
<p>Avec Django 1.6 qui vient de sortir hier, j&#8217;ai pu m’apercevoir que <a href="http://sametmax.com/django-quicky-labolition-des-preliminaires-par-sam-et-max/">django-quicky</a> ne marchait plus sur cette nouvelle version. Un sombre histoire de <code>setup_environ</code> qui est deprecated. Comme je l&#8217;utilise (ce qui est mieux avec les outils qu&#8217;on code ^^), j&#8217;ai fait un petit correctif vite-fait.</p>
<p>J&#8217;en ai profité aussi pour ajouter deux fichiers de requirements avec des apps Python que j&#8217;installe très très souvent pour mes projets.</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=7716&amp;md5=be71a871dc7dfb8dc4e81752048c781e" title="Flattr" target="_blank"><img src="media/fc229d00.flattr-badge-large.png" data-original-source="http://sametmax.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>


feed_id: http://sametmax.com/?p=7698
uri: Preprocesser-ses-fichiers-statiques-et-recharger-son-navigateur-automa
title:
Preprocesser ses fichiers statiques et recharger son navigateur automatiquement avec Python livereload

url:
http://sametmax.com/preprocesser-ses-fichiers-statiques-et-recharger-son-navigateur-automatiquement-avec-python-livereload/

content:
<p>Livereload est une extension multi-navigateur qui permet de recharger tout ou partie d&#8217;une page quand un fichier a changé sur le disque. </p>
<p>C&#8217;est très pratique pour développer un site Web puisque si vous modifiez un template, un fichier JavaScript, une image ou un fichier CSS, vous n&#8217;avez pas besoin de cliquer sur la fenêtre du navigateur et appuyez sur F5 pour voir le résultat. Si vous avez un double écran (et si vous faites du dev Web, vous devriez), vous ne quittez pas votre éditeur de code.</p>
<p>L&#8217;extension est gratuite, mais le serveur existe en plusieurs version. Il y a une version graphique pour Windows et Mac qui est payante. Si vous avez un peu de budget et pas envie de vous prendre la tête, <a href="http://livereload.com/">achetez là</a> et arrêtez la lecture de l&#8217;article, c&#8217;est beaucoup plus facile.</p>
<p>Sinon, suivez le guide pour la version gratos en ligne de commande.</p>
<h2>Installation</h2>
<p>Il existe une version Python en ligne de commande du serveur : <a href="http://livereload.readthedocs.org/en/latest/install.html">Python livereload</a>. Il y a aussi <a href="https://github.com/guard/guard-livereload">une version pour les rubistes</a>.</p>
<p>Je vous invite donc à l&#8217;installer avec <a href="http://sametmax.com/votre-python-aime-les-pip/">pip</a>:</p>

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

<p>Il vous faudra aussi l&#8217;<a href="http://feedback.livereload.com/knowledgebase/articles/86242-how-do-i-install-and-use-the-browser-extensions-">extension de navigateur</a>.</p>
<p>Après, depuis votre terminal, mettez vous dans le dossier que vous voulez surveiller (par exemple le dossier contenant vos fichiers CSS), et lancez le serveur :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">livereload</pre></div></div>

<p>Et activez l&#8217;extension pour la page que vous voulez recharger automatiquement. Normalement, c&#8217;est juste un clic sur un bouton.</p>
<p>C&#8217;est bon, votre page devrait recharger automatiquement.</p>
<h2>Rechargement à la carte</h2>
<p>On peut choisir ce qu&#8217;on va recharger plus précisément en créant un fichier de configuration.</p>
<p>Créez un fichier de code Python nommé &#8220;Guardfile&#8221;, sans l&#8217;extension &#8220;.py&#8221;. Il va ressembler à ceci :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #808080; font-style: italic;">#!/usr/bin/env python</span>
<span style="color: #808080; font-style: italic;"># -*- coding: utf-8 -*-</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">from</span> livereload.<span style="color: black;">task</span> <span style="color: #ff7700;font-weight:bold;">import</span> Task
&nbsp;
<span style="color: #808080; font-style: italic;"># watcher les js ou les css</span>
Task.<span style="color: black;">add</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'chemin/relatif/vers/fichier/a/surveiller.css'</span><span style="color: black;">&#41;</span>
Task.<span style="color: black;">add</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'chemin/relatif/vers/fichier/a/surveiller.js'</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># watcher les images ou les templates</span>
Task.<span style="color: black;">add</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'chemin/relatif/vers/dossier/a/surveiller'</span><span style="color: black;">&#41;</span></pre></div></div>

<p>Et lancez la commande <code>livereload</code> <strong>en étant dans le même dossier que ce fichier</strong>. Notez que le serveur ne parse ce fichier que quand l&#8217;extension est activée et que vous avez visité la page au moins une fois.</p>
<p>On peut même demander d&#8217;effectuer des tâches avant le rechargement de la page. Cela peut être des tâches complètement arbitraires, mais des raccourcis existent pour les tâches les plus courantes, telle que minifier du JS ou compiler un pre-processeur CSS.</p>
<p>Par exemple, j&#8217;utilise cette fonctionnalité pour compiler mes fichiers LESS CSS à chaque modification.</p>
<p>Pour cela, il faut installer le compilateur LESS. Sous Ubuntu, ça se fait en deux coups de cuillère à pot :</p>

<div class="wp_syntax"><div 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</span> <span style="color: #c20cb9; font-weight: bold;">install</span> npm
<span style="color: #c20cb9; font-weight: bold;">sudo</span> npm <span style="color: #c20cb9; font-weight: bold;">install</span> <span style="color: #660033;">-g</span> <span style="color: #c20cb9; font-weight: bold;">less</span></pre></div></div>

<p>Et dans le Guardfile, il faut ajouter un code du style :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">from</span> livereload.<span style="color: black;">task</span> <span style="color: #ff7700;font-weight:bold;">import</span> Task
<span style="color: #ff7700;font-weight:bold;">from</span> livereload.<span style="color: #dc143c;">compiler</span> <span style="color: #ff7700;font-weight:bold;">import</span> lessc
&nbsp;
Task.<span style="color: black;">add</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'../apps/core/static/less/boostrap/boostrap.less'</span>,
         lessc<span style="color: black;">&#40;</span><span style="color: #483d8b;">'../apps/core/static/less/boostrap/boostrap.less'</span>,
               <span style="color: #483d8b;">'../apps/core/static/css/boostrap.css'</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span></pre></div></div>

<p>Il y a un a tas d&#8217;options donc checkez la doc, mais aussi le code source car la doc n&#8217;est pas exhaustive.</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=7698&amp;md5=ed86fc2e901610edc857027027b71659" title="Flattr" target="_blank"><img src="media/fc229d00.flattr-badge-large.png" data-original-source="http://sametmax.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>


