# articles

feed_id: http://sametmax.com/?p=6995
title: AMA reddit
uri: AMA-reddit
url: http://sametmax.com/ama-reddit/
content:
<p>Un lecteur nous a proposé ça par mail :</p>
<blockquote><p>Bonjour Sam &#038; Max,</p>
<p>Il serait d&#8217;utilité publique si vous pouviez faire un AMA reddit sur python et l&#8217;industrie du pron !</p>
<p>Je suis sérieux.</p>
<p>Bonne semaine Heckel et Jeckel !
</p></blockquote>
<p>Ça intéresse d&#8217;autres personnes ? Si oui, quel interêt de le faire sur reddit plutôt que sur le blog ? Quel est la meilleur période pour le faire ? Quelle est la marche à suivre ? Pourquoi les torrents qui buggent le font toujours à 99% et jamais à 1% ?</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=6995&amp;md5=dce9dc7a95dd7f1288c57c2ca34cb1f2" 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=7011
title: Organisation d’une application Django
uri: Organisation-d-une-application-Django
url: http://sametmax.com/organisation-dune-application-django/
content:
<p>Article long, tradition :</p>

<!-- iframe plugin v:2.3 - wordpress.org/extend/plugins/iframe/ -->
<iframe width="420" height="315" src="//www.youtube.com/embed/o3e5EanH4sk" frameborder="0" scrolling="no" class="iframe-class"></iframe>
<p>Question qui est arrivée par le formulaire de contact il y a prêt de 2 mois (désolé ^^), et que je m&#8217;étais posé également en commençant avec ce framework.</p>
<p>En effet, Django, c&#8217;est du pur Python. On peut structurer son projet comme on veut. On pourrait même tout mettre dans un seul dossier : les vues, les templates, le css. Tout.</p>
<p>Mais ce n&#8217;est pas parce que c&#8217;est possible qu&#8217;il faut le faire, et nous allons donc voir les bonnes pratiques.</p>
<p>WARNING : je vais soigneusement ignorer la question des settings, qui mérite un article à part entière.</p>
<h2>Naissance du projet</h2>
<p>Quand vous commencez un projet avec <code>startproject</code> et <code>startapp</code>, vous allez avoir une arborescence qui va ressembler ça ceci :</p>
<pre>.
├── manage.py
├── mon_app
│   ├── __init__.py
│   ├── models.py
│   ├── tests.py
│   └── views.py
└── project
    ├── settings.py
    ├── urls.py
    └── wsgi.py</pre>
<p>Avec ça, on ne fait pas une app, vous allez donc ajouter des formulaires, de l&#8217;admin, des templates, du js, du css&#8230;</p>
<p>Pour tout ce qui est fichier statique (JS, CSS, images, flash, zips&#8230;), la bonne pratique Django est de mettre tout ce qui concerne l&#8217;app dans un dossier nommé <em>static</em> à l&#8217;interieur de l&#8217;app. Django vient en effet avec <a href="http://sametmax.com/comment-servir-les-fichiers-statiques-avec-django-en-dev-et-en-prod/">tous les outils</a> pour les gérer de cette manière.</p>
<p>Pour l&#8217;admin et les formulaires, il est d&#8217;usage de les mettre dans des modules <em>admin.py</em> et <em>forms.py</em> respectivement.</p>
<p>Quand au template, la bonne pratique est de les mettre dans un sous dossier de l&#8217;app nommé <em>template</em> comme pour les fichiers statiques. MAIS, chaque template doit aussi être dans un sous dossier qui porte le nom de l&#8217;app. Cela donne :</p>
<p><em>nom_de_lapp/templates/nom_de_lapp/template.html</em></p>
<p>La raison à cela est que cela permet à d&#8217;autres app de pourvoir utiliser le même nom de template, ou d&#8217;écraser votre template explicitement. Inversement votre app peut dans ses templates écraser les templates d&#8217;une autre app en ayant un template avec le chemin :</p>
<p><em>nom_de_lapp/templates/nom_de_lautre_app/template.html</em></p>
<p>Donc, même si cela parait redondant, toujours créer un sous-dossier avec le nom de l&#8217;app dans le dossier <em>templates</em>. Cela se fait de plus en plus avec le dossier <em>static</em> également, mais c&#8217;est moins important dans un premier temps pour vous car vous n&#8217;allez pas publier ces apps. Donc, vous pouvez ne pas le faire pour <em>static</em> pour le moment.</p>
<p>Enfin, je vous recommande d&#8217;avoir toujours les routes qui concernent votre app dans un fichier <em>urls.py</em> dans le dossier de l&#8217;app, qui sera inclus par celui du projet. Cela vous aidera pour la suite.</p>
<p>Votre arbo de base va donc ressembler à ça :</p>
<pre>.
├── manage.py
├── mon_app
│   ├── admin.py
│   ├── forms.py
│   ├── __init__.py
│   ├── models.py
│   ├── static
│   │   ├── css
│   │   │   └── style.css
│   │   └── js
│   │       └── behavior.js
│   ├── templates
│   │   └── mon_app
│   │       └── index.html
│   ├── tests.py
│   ├── urls.py
│   └── views.py
└── project
    ├── settings.py
    ├── urls.py
    └── wsgi.py</pre>
<h2>Croissance du projet</h2>
<p>Jusqu&#8217;ici votre projet était un petit site avec quelques vues, un formulaire, 3 modèles, et c&#8217;est tout. Mais il a grandi, et comme dans toute adolescence, ça commence à être le bordel dans la chambre : le fichier <em>views.py</em> contient 25 fonctions courtes, le fichier <em>models.py</em> 4 classes mais fait 800 lignes.</p>
<p>La première chose à faire à ce niveau, c&#8217;est de transformer les modules en packages.</p>
<p>Souvenez-vous : la règle la plus importante avec Django, c&#8217;est que c&#8217;est juste du Python.</p>
<p>On peut donc prendre chaque fichier de modules, et les diviser en plusieurs sous fichiers (chacun représentant un jeu de fonctionnalités), puis les mettre dans un packages. Pour rappel, un package c&#8217;est un dossier avec un fichier <em>__init__</em>.</p>
<p>Exemple, vous avez views.py qui ressemble à ç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> home<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> user_account<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> <span style="color: #dc143c;">profile</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> messages<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> forum<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> articles<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:</pre></div></div>

<p>Vous allez faire un dossier <em>views</em> avec fichier <em>__init__</em> et 3 modules :</p>
<pre>
views
├── communication.py <= contient formum() et messages()
├── content.py  <= contient articles() et home()
├── __init__
└── user.py  <= contient user_account() et profile()</pre>
<p>A vous de trouver des noms explicites. Prenez le temps de le faire, un bon nom, c'est 10 lignes de documentation en moins.</p>
<p>Maintenant concernant les imports, vous allez devoir faire :</p>
<pre class="python">from mon_app.views.content import home</pre>
<p>Au lieu de :</p>
<pre class="python">from mon_app.views import home</pre>
<p>Si cela vous ennuie, il est tout ça fait possible de faire dans <em>__init__.py</em> :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">from</span> communcation <span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #66cc66;">*</span>
<span style="color: #ff7700;font-weight:bold;">from</span> content <span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #66cc66;">*</span>
<span style="color: #ff7700;font-weight:bold;">from</span> <span style="color: #dc143c;">user</span> <span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #66cc66;">*</span></pre></div></div>

<p>Et vous n'aurez pas à changer le moindre de vos imports. Pour Python, un module et un package, c'est pareil.</p>
<p>Si votre app devient grosse, je vous invite quand même a réserver les imports dans <em>__init__</em> pour les fonctions les plus courantes, afin de ne pas saturer l'auto-completion quand vous êtes dans le shell ou dans votre IDE.</p>
<p>Bref, si vous appliquez cela à tous vos modules un peu gras, ça peut donner :</p>
<pre>.
├── manage.py
├── mon_app
│   ├── admin.py
│   ├── forms
│   │   ├── communication.py
│   │   ├── __init__.py
│   │   └── user.py
│   ├── __init__.py
│   ├── models
│   │   ├── content.py
│   │   ├── __init__.py
│   │   ├── stats.py
│   │   └── user.py
│   ├── static
│   │   ├── css
│   │   │   └── style.css
│   │   └── js
│   │       └── behavior.js
│   ├── templates
│   │   └── mon_app
│   │       └── index.html
│   ├── tests.py
│   ├── urls.py
│   └── views
│       ├── communication.py
│       ├── content.py
│       ├── __init__
│       └── user.py
└── project
    ├── settings.py
    ├── urls.py
    └── wsgi.py</pre>
<p>Votre app commence vraiment à prendre du poids, mais ça reste manageable. Notez que ceci peut s'appliquer à n'importe quel module qui devient trop gros, y compris <em>admin.py</em> ou <em>urls.py</em>. Généralement ce sont <em>views.py</em> et <em>models.py</em> qui grossisent les premiers, suivi de <em>tests.py</em>. <em>tests.py</em> devrait en principe être celui qui grossi le plus, mais je sais bien que chez la plupart des gens, ce fichier est vide.</p>
<h2>Maturité</h2>
<p>Tout centraliser au début facilite la tâche. On trouve tout facilement, pas de souci de gestion, ça permet de commencer rapidement. Sur le long terme, le code va s'accumuler et il va devenir difficile de trouver ce que l'on cherche, avoir une image globale de ce qui se passe ou faire des modifications. Mais le pire, c'est pour le partage et la réutilisation de code.</p>
<p>Votre projet est un grand garçon, il est temps de le traiter comme tel.</p>
<p>Cela va passer par la division de votre grosse application monolithique, en plusieurs apps plus petites, chacune représentant une fonctionnalité ou un groupe de fonctionnalités. Au début ce concept de "groupe de fonctionnalités" est difficile à appréhender pour un débutant, alors commencez par faire simple : faites une app par 'partie du site' comme par exemple le dashboard, le forum, le compte utilisateur, etc. On peut faire mieux, mais ce sera déjà bien.</p>
<p>Plus tard, quand vous serez plus à l'aise avec ce principe, vous pourrez étudier la notion de "composants" et de "pluggable apps" qui vous amèneront à faire des applications réutilisables (et même partageables sur le Net) orientées fonctionalités : messaging, comments, anti-spam, registration, user management, etc. Mais cela implique bien d'autres choses qui sont en dehors du cadre de cet article. Pour le moment, concentrez-vous sur la division de votre grosse app en plusieurs plus petites.</p>
<p>Dans notre exemple on note qu'il y a 3 grosses parties : une partie "information", une partie "communication" et une partie "contenu". Nos apps sont donc toutes trouvées.</p>
<p>Il n'est pas rare non plus d'avoir des petits bouts dont on ne sait quoi faire, et aussi des fondations de code qui ne se prêtent pas vraiment à être mis dans une app, comme la home page ou le miniscule modèle stats qui ici n'est pas encore assez gros. Dans ce cas, il suffit de créer une application principale qui va contenir tout ça, en attendant que vous vienne l'inspiration de classifier / factoriser / répartir son contenu ailleurs. J'appelle souvent cette app "core", à défaut d'un meilleur nom.</p>
<pre>.
├── communication
│   ├── admin.py
│   ├── forms.py
│   ├── __init__.py
│   ├── templates
│   │   └── communcation
│   │       └── forum.html
│   ├── tests.py
│   ├── urls.py
│   └── views.py
├── content
│   ├── admin.py
│   ├── __init__.py
│   ├── models.py
│   ├── tests.py
│   ├── urls.py
│   └── views.py
├── core
│   ├── admin.py
│   ├── __init__.py
│   ├── static
│   │   ├── css
│   │   │   └── style.css
│   │   └── js
│   │       └── behavior.js
│   ├── templates
│   │   └── mon_app
│   │       └── index.html
│   ├── tests.py
│   ├── urls.py
│   └── views.py
├── manage.py
├── project
│   ├── settings.py
│   ├── urls.py
│   └── wsgi.py
└── user
    ├── admin.py
    ├── forms.py
    ├── __init__.py
    ├── models.py
    ├── templates
    │   └── user
    │       └── profile.html
    ├── tests.py
    ├── urls.py
    └── views.py</pre>
<p>Vous noterez des phénomènes intéressants :</p>
<ul>
<li>Une app n'a pas forcément besoin de contenir models + urls + templates... Une partie suffisament grosse, indépendante et spécialisée justifie d'être déplacée dans une app.</li>
<li>Les packages <em>views</em> et <em>models</em> sont redevenus des fichiers. On pourra les transformer à nouveau en package quand ils grossiront.</li>
<li>Il y a des templates qui ont magiquement apparu. La raison à cela, c'est que en écrivant le tuto j'ai oublié de faire suivre le nombre de fichiers statiques et de templates pour qu'ils correspondent aux fonctionnalités et du coup je me retrouve comme un con :-) Alors vous allez faire comme si vous avez rien vu, et comme si ils étaient là depuis le départ, parce que j'ai pas le courage de tout refaire.</li>
<li>Il n'y a pas de model dans communication. Ca n'a aucun sens. Même problème que précédemment. C'est un exemple, bordel !</li>
<li><em>static</em> est resté dans <em>core</em>. Ca c'est très courant. Au début vous n'aurez pas de fichiers statiques répartis entre les apps. Avec le temps, ça vient. Mais généralement ça se fait en dernier car ça demande de vraiment bien penser son archi.</li>
<li>Chaque app a gagné un fichier <em>urls.py</em> qui doit donc être inclus dans <em>project/urls.py</em>. Il est parfaitement acceptable d'avoir un app qui n'a pas d'<em>urls.py</em> (ou de <em>models.py</em>, ou de forms, ou de presque rien de tout ça). Simplement je pense que ça sera plus facile pour vous de penser dans un premier temps avec des "parties de site" et donc des urls.</li>
</ul>
<p>Au début, vos apps seront fortement couplées. Avec l'expérience (et peut être un article), vous apprendrez à les rendre de plus en plus autonomes, et finalement à avoir un maximum d'apps génériques et quelques apps glues. Je vous rassure, nos codes en prod à Max et moi sont pleins de couplages également. Il y a la théorie, et le résultat de 200 mises en prod.</p>
<p>Bref, vous allez ensuite faire grossir vos applications organiquement comme on a vu dans <em>Croissance du projet</em> et quand elles dépassent une masse critique (<a href="media/8040d718.wtfm.jpg" data-original-source="http://crypt.codemancers.com/assets/images/wtfm.jpg">mesurable scientifiquement</a>), vous la splitter en apps plus petites, et ainsi de suite.</p>
<h2>L'age de raison</h2>
<p>Après de nombreuses mises en production, des tentatives d'automatisation, des fichiers de conf qui vont trainer, des fichiers statiques et des libs ajoutées, vous allez vous apercevoir que même cette archi commence à être brouillonne.</p>
<p>Il est temps de passer en mode pro.</p>
<p>Alors, attention, à partir de la, on tombe dans la guerre de religion : VI VS Emacs, PC VS Mac, Bigoo VS Big Mac, Ulysse VS Télémaque, etc. Bref, le layout d'une application en Django a fait coulé beaucoup d'encre et je ne vous propose qu'une des versions possibles.</p>
<p>D'abord, on va regrouper les apps dans un dossier pour éviter d'avoir 20000 dossiers à la racine.</p>
<pre>.
├── apps
│   ├── communication
│   │   └── templates
│   │       └── communcation
│   ├── content
│   ├── core
│   │   ├── static
│   │   │   ├── css
│   │   │   └── js
│   │   └── templates
│   │       └── mon_app
│   └── user
│       └── templates
│           └── user
└── project</pre>
<p>Afin de toujours permettre d'importer les apps directement et non et les préfixant de 'apps', vous pouvez ajouter le chemin au <code>PYTHON PATH</code> dans le fichiers de settings:</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;">os</span>
<span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">sys</span>
&nbsp;
PROJECT_DIR = <span style="color: #dc143c;">sys</span>.<span style="color: black;">path</span>.<span style="color: black;">append</span><span style="color: black;">&#40;</span><span style="color: #dc143c;">os</span>.<span style="color: black;">path</span>.<span style="color: black;">dirname</span><span style="color: black;">&#40;</span><span style="color: #dc143c;">os</span>.<span style="color: black;">path</span>.<span style="color: black;">realpath</span><span style="color: black;">&#40;</span>__file__<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
APPS_DIR = <span style="color: #dc143c;">os</span>.<span style="color: black;">path</span>.<span style="color: black;">realpath</span><span style="color: black;">&#40;</span><span style="color: #dc143c;">os</span>.<span style="color: black;">path</span>.<span style="color: black;">join</span><span style="color: black;">&#40;</span>PROJECT_DIR, <span style="color: #483d8b;">'..'</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
<span style="color: #dc143c;">sys</span>.<span style="color: black;">path</span>.<span style="color: black;">append</span><span style="color: black;">&#40;</span>APPS_DIR<span style="color: black;">&#41;</span></pre></div></div>

<p>Ce n'est pas obligatoire, mais ça facilite beaucoup la vie, et la refactorisation.</p>
<p>Ensuite, il va vous falloir un dossier dans lequel mettre les fichiers de confs (requirements.txt, templates de fichiers de conf nginx, postgres, redis, etc) et les scripts de déploiements, et un autre pour la doc. Je le mets en général dans <em>project</em>. Si Max lit jusqu'à cette ligne, il va bien se marrer, vu le bordel qu'il y a dans les arbos de certains de nos projets.</p>
<pre>.
├── apps
│   ├── communication
│   │   └── templates
│   │       └── communcation
│   ├── content
│   ├── core
│   │   ├── static
│   │   │   ├── css
│   │   │   └── js
│   │   └── templates
│   │       └── mon_app
│   └── user
│       └── templates
│           └── user
└── project
    ├── deploy
    └── doc
</pre>
<p>Tous ces fichiers doivent être commités dans un VCS (Git, SVN, mercurial...).</p>
<p>A cela, il faut souvent ajouter une dossier <em>libs</em> qui contient toutes les libs non installables par pip, tous vos forks, vos trucs compilés avec des options zarbs, vos libs persos non Django qui ne sont pas sur pypi, etc. Dans le meilleur des mondes, il vous faut récupérer son contenu dynamiquement avec un script. Dans le meilleur des mondes... Sinon, ajoutez le à votre VCS. Et par simplicité, ajoutez ce dossier au <code>PYTHON PATH</code>.</p>
<p>Ensuite il faut un dossier <em>var</em>, qui va contenir tous ce qui est fichier que le code du projet va manipuler : fichiers statiques collectés par <code>./manage.py collectstatic</code>, fichiers de log, base de données SQLite, dumps, locks, etc.</p>
<p>Puis il faut un dossier <em>etc</em> dans lequel on va mettre les fichiers de configuration pour le projet, pour ce serveur : le fichiers conf nginx, postgres, redis qui auront été générés depuis le templates situés dans <em>project/deploy/</em>. Faites ensuite un lien symbolique depuis ces fichiers dans les dossiers correspondant (par exemple vers /etc/nginx/site-enabled pour un fichier de config nginx).</p>
<p>Ces deux dossiers sont nommés ainsi car c'est la nomenclature des dossiers pour cet usage sous Linux, mais vous pouvez leur donner le nom que vous voulez.</p>
<p>Dans tous les cas, ce sont des dossiers qui ne sont PAS commités dans votre VCS, donc mettez les dans votre blacklist (type <em>.gitignore</em>). Ils sont spécifiques à une installation.</p>
<p>Idéalement il faut les générer avec un truc genre <a href="http://sametmax.com/travailler-moins-pour-gagner-plus-en-15-minutes-avec-python-fabric/">fabric</a> pour pas avoir à le faire à la main, même si vous apprendrez mieux en le faisant à la mano au début. Générer ses fichiers de conf avec des templates, c'est un idéal. Après, il y a vraiment une boîte sur 10 qui le fait dans la pratique.</p>
<p>Puis vous ajoutez un <em>README</em> qui explique rapidement quel dossier contient quoi, où trouver la doc et particulièrement, pointez directement vers la partie de la doc sur l'installation et les dépendances.</p>
<pre>.
├── apps
│   ├── communication
│   ├── content
│   ├── core
│   └── user
├── etc
├── libs
├── project
│   ├── deploy
│   └── doc
└── var
└── README.rst</pre>
<p>Souvent, je met aussi un symlink du virtualenv à la racine du projet, car c'est très pratique pour jeter un coup d'oeil dans le site-packages.</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=7011&amp;md5=33054178a7ef6f6995bf8ed33b480f9b" 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=7003
title: Question d’un lecteur sur le cache et Django
uri: Question-d-un-lecteur-sur-le-cache-et-Django
url: http://sametmax.com/question-dun-lecteur-sur-le-cache-et-django/
content:
<p>Encore un message du formulaire de contact auquel je n&#8217;arrive pas à répondre (delivery failure).</p>
<blockquote><p>
> Subject: Idée d&#8217;article/Question<br />
><br />
> Message Body:<br />
> Salut !<br />
><br />
> Merci pour vos articles décalés et ceux qui sont plus au centre.<br />
><br />
> J&#8217;ai une petite question sur Django :<br />
> Est-ce possible de mettre toutes les résultats de requetes de l&#8217;ORM de<br />
Django dans memcached, et de les récupérer / mettre à jour / supprimer ?<br />
> Pour moi ça bloque au niveau de la mise à jour / suppression.<br />
><br />
> Du coup je me suis dit que vous pourriez faire un article sur les<br />
différentes méthodes de mise en cache dans Django et ce que on peut<br />
faire avec.</p></blockquote>
<p>Hello,</p>
<p>Oui, c&#8217;est possible.</p>
<p>La mise à jour et la suppression du cache a toujours été une des choses<br />
les plus difficiles en programmation, donc c&#8217;est naturel de bloquer dessus.</p>
<p>Pour commencer, utilise <a href="https://github.com/jbalogh/django-cache-machine">django-cache-machine</a> ou <a href="http://pythonhosted.org/johnny-cache/">johnny-cache</a>, qui sont des<br />
surcouche à l&#8217;ORM Django avec cache automatique. Ensuite, tu apprendras<br />
à faire le reste à la main petit à petit.</p>
<p>Pour les pages complètes, des solutions qui n&#8217;ont rien à avoir avec<br />
Django, telles que Varnish, sont aussi des approches qui permettent de<br />
gagner pas mal en perfs.</p>
<p>Bref, je note ce truc dans la liste des articles à faire.</p>
<p>Sam</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=7003&amp;md5=7d4f5cbd233cd9551739e8f155916c75" 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=7024
title: Planescape Torment et Fallout 1, version moderne
uri: Planescape-Torment-et-Fallout-1-version-moderne
url: http://sametmax.com/planescape-torment-et-fallout-1-version-moderne/
content:
<p>En attendant <a href="http://www.kickstarter.com/projects/inxile/torment-tides-of-numenera">Tides of Numenera</a>, le fantastique site Web <a href="http://gog.com/">GOG</a> fournit pour de faibles sommes des heures de plaisir sur Theme Hostpital, Baldur&#8217;s Gate ou Heroes Of Might and Magic 3 avec un installeur No CD légal qui fonctionne sur un OS moderne.</p>
<p>Oui mais voilà, si vous voulez rejouer à des monuments comme Planescape Torment ou Fallout 1 sur votre écran 16/9, vous allez très vite ressentir un fort picotement rectal. En effet, ces jeux sont prévus pour des résolutions très basses. Déjà que ces oldies sont tellement pixélisés que la plupart des dialogues ressemblent à &#8220;bonjour carré, moi c&#8217;est triangle&#8221;, mais en 1920&#215;1080, ça fait carrément Picasso période albinos.</p>
<p>Heureusement, il y a des fans qui ont travaillés gratuitement avec acharnement à moder ces jeux aux cours des années, avec <a href="http://www.youtube.com/watch?v=4GejCUObcfA">des résultats épatant</a> (ceux qui ont joué à l&#8217;original comprendront mieux que les amateurs de COD, évidement). Plus que ça, l&#8217;ergonomie a largement été améliorée, avec du stacking d&#8217;objets, des quêtes restaurées, des bugs corrigés, etc. C&#8217;est beau.</p>
<p>On trouve des tutos pour <a href="http://thunderpeel2001.blogspot.fr/2009/01/planescape-torment-fully-modded.html">Planescape Torment</a> et <a href="http://falloutmods.wikia.com/wiki/Fallout_1_Mods">Fallout 1</a> un peu partout.</p>
<p>Sur ce, je vais aller boire un Nuke Cola.</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=7024&amp;md5=62773b3288dba9355336083268152342" 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=7029
title: Garder une video flash en full screen et travailler sur un autre écran
uri: Garder-une-video-flash-en-full-screen-et-travailler-sur-un-autre-écra
url: http://sametmax.com/garder-une-video-flash-en-full-screen-et-travailler-sur-un-autre-ecran/
content:
<p>Vous avez deux écrans. Vous regardez un tuto video sur le premier, et vous testez le code sur le deuxième. Malheureusement, impossible de mettre la vidéo en plein écran, car à peine avez vous cliqué sur le deuxième, que la vidéo retourne en mode réduit.</p>
<p>Il existe un hack pour pallier ce problème.</p>
<p>J&#8217;ai bien dis un hack. Un truc moche, dont les conséquences sont mal connues. Mais ça marche, c&#8217;est bien pratique, et je suis d&#8217;ailleurs en train de rédiger cet article avec le premier épisode de <a href="http://www.dpstream.net/serie-5409-aj.html#js5409-,-1-,-01%20[VOST%20FR]">Vikings</a> en fond.</p>
<p>D&#8217;abord, il faut chopper un éditeur héxadécimal.</p>
<p>N&#8217;importe lequel fera l&#8217;affaire, moi sous Ubuntu j&#8217;utilise Ghex :</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> ghex</pre></div></div>

<p>Il va vous falloir ouvrir le binaire flash avec. Yes, à l&#8217;ancienne. </p>
<p>La position du binaire est différent pour chaque OS. Je ne sais pas où il est sous Windows (ça doit être une DLL planquée dans system32 ou un truc du genre), mais sous Ubuntu (et surement sous n&#8217;importe quel Unix comme Red hat ou Max), on trouve le fichier facilement :</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">$ <span style="color: #c20cb9; font-weight: bold;">locate</span> libflashplayer.so
<span style="color: #000000; font-weight: bold;">/</span>usr<span style="color: #000000; font-weight: bold;">/</span>lib<span style="color: #000000; font-weight: bold;">/</span>flashplugin-installer<span style="color: #000000; font-weight: bold;">/</span>libflashplayer.so</pre></div></div>

<p>Du coup, on édite le fichier avec l&#8217;éditeur hexa en mode admin :</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">$ <span style="color: #c20cb9; font-weight: bold;">sudo</span> ghex <span style="color: #000000; font-weight: bold;">/</span>usr<span style="color: #000000; font-weight: bold;">/</span>lib<span style="color: #000000; font-weight: bold;">/</span>flashplugin-installer<span style="color: #000000; font-weight: bold;">/</span>libflashplayer.so</pre></div></div>

<p>Il faut ensuite recherche la chaîne <code>_NET_ACTIVE_WINDOW</code>.</p>
<p>Pour ghex, c&#8217;est dans, le menu recherche est dans <em>Édition > Rechercher</em> :</p>
<div id="attachment_7034" class="wp-caption aligncenter" style="width: 336px"><a href="media/71129d71.recherche_ghex.jpg" data-original-source="http://sametmax.com/wp-content/uploads/2013/08/recherche_ghex.jpg"><img src="media/71129d71.recherche_ghex.jpg" data-original-source="http://sametmax.com/wp-content/uploads/2013/08/recherche_ghex.jpg" alt="Capture d&#039;écran de la fenêtre de recherche du logiciel ghex" title="Attention, ne faites pas de copier / coller. Tapez la chaîne à la main." width="326" height="235" class="size-full wp-image-7034" /></a><p class="wp-caption-text">Attention, ne faites pas de copier / coller. Tapez la chaîne à la main.</p></div>
<p>Dans ce logiciel, la recherche sous forme de texte se fait dans <strong>la partie droite de la fenêtre</strong>.</p>
<p>L&#8217;éditeur va surligner le terme de la recherche, et va falloir cliquer sur n&#8217;importe quelle lettre et la remplacer par une autre. </p>
<div id="attachment_7031" class="wp-caption aligncenter" style="width: 442px"><a href="media/c189acae.libflashplayer.so-GHex_005.jpg" data-original-source="http://sametmax.com/wp-content/uploads/2013/08/libflashplayer.so-GHex_005.jpg"><img src="media/c189acae.libflashplayer.so-GHex_005.jpg" data-original-source="http://sametmax.com/wp-content/uploads/2013/08/libflashplayer.so-GHex_005.jpg" alt="Capture d&#039;écran de la fenêtre principale du logiciel ghex" title="Pareil, tout se passe dans la partie droite de la fenêtre" width="432" height="300" class="size-full wp-image-7031" /></a><p class="wp-caption-text">Pareil, tout se passe dans la partie droite de la fenêtre</p></div>
<p>Oui, oui, techniquement on est en train de créer un bug en détruisant le nom d&#8217;une constante.</p>
<p>Pour faire le remplacement sous Ghex, pas besoin de faire un backspace, un suprr, ou quoi que ce soit : cliquez sur une lettre de la sélection, appuyez sur une lettre de votre clavier, et c&#8217;est bon.</p>
<p><strong>Attention : il va falloir maintenant sauver votre travail, ce qui va faire planter toute app ou video flash en cours.</strong></p>
<p>C&#8217;est tout, vous pouvez retournez sur Youtube.</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=7029&amp;md5=ec7cbfa461380308e2ff3dc64d4f4494" 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=7042
title: Les expressions rationnelles en Python, parfois overkill
uri: Les-expressions-rationnelles-en-Python-parfois-overkill
url: http://sametmax.com/les-expressions-rationnelles-en-python-parfois-overkill/
content:
<p>J&#8217;adore les regex, et d&#8217;ailleurs il faudra que je fasse une série d&#8217;articles sur le sujet, un peu comme le guide de la POO.</p>
<p>Mais dans un langage comme Python, il y a de nombreuses solutions à mettre en oeuvre avant d&#8217;utiliser les regex.</p>
<p>Pour vérifier si une chaîne est dans une autre, utilisez <code>in</code> :</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;">'a'</span> <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #483d8b;">'chat'</span>
<span style="color: #008000;">True</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #483d8b;">'a'</span> <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #483d8b;">'chien'</span>
<span style="color: #008000;">False</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #483d8b;">'a'</span> <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #483d8b;">'CHAT'</span>.<span style="color: black;">lower</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span> <span style="color: #808080; font-style: italic;"># ignorer la casse</span>
<span style="color: #008000;">True</span></pre></div></div>

<p>Pour savoir si un chaîne est au début ou à la fin, utilisez <code>startswith()</code> et <code>endswith()</code> :</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;">'achat'</span>.<span style="color: black;">startswith</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'a'</span><span style="color: black;">&#41;</span>
<span style="color: #008000;">True</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #483d8b;">'chat'</span>.<span style="color: black;">startswith</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'a'</span><span style="color: black;">&#41;</span>
<span style="color: #008000;">False</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #483d8b;">'acheta'</span>.<span style="color: black;">endswith</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'a'</span><span style="color: black;">&#41;</span>
<span style="color: #008000;">True</span></pre></div></div>

<p>Pour savoir si la chaîne est d&#8217;un type particulier, utiliser les méthodes <code>is*</code> :</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;">'555'</span>.<span style="color: black;">isdigit</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
<span style="color: #008000;">True</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #483d8b;">''</span>.<span style="color: black;">isdigit</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
<span style="color: #008000;">False</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #483d8b;">'⑦'</span>.<span style="color: black;">isdigit</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
<span style="color: #008000;">True</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #483d8b;">'444'</span>.<span style="color: black;">isdecimal</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
<span style="color: #008000;">True</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #483d8b;">'444.55'</span>.<span style="color: black;">isdecimal</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
<span style="color: #008000;">False</span>
<span style="color: #66cc66;">&gt;&gt;</span> <span style="color: #483d8b;">'⑦'</span>.<span style="color: black;">isdecimal</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
<span style="color: #008000;">False</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #483d8b;">'879fds'</span>.<span style="color: black;">isalpha</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
<span style="color: #008000;">False</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #483d8b;">'fsdqfsqd'</span>.<span style="color: black;">isalpha</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
<span style="color: #008000;">True</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #483d8b;">'fsdqfsqd'</span>.<span style="color: black;">islower</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
<span style="color: #008000;">True</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #483d8b;">'fsdqFFsqd'</span>.<span style="color: black;">islower</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
<span style="color: #008000;">False</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #483d8b;">'879fds'</span>.<span style="color: black;">isalnum</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
<span style="color: #008000;">True</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #483d8b;">'879fds-'</span>.<span style="color: black;">isalnum</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
<span style="color: #008000;">False</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #483d8b;">' <span style="color: #000099; font-weight: bold;">\t</span><span style="color: #000099; font-weight: bold;">\n</span>'</span>.<span style="color: black;">isspace</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
<span style="color: #008000;">True</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #483d8b;">' <span style="color: #000099; font-weight: bold;">\t</span><span style="color: #000099; font-weight: bold;">\n</span> fdsfd'</span>.<span style="color: black;">isspace</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
<span style="color: #008000;">False</span></pre></div></div>

<p>Si vous voulez manipuler la chaîne pour en extraire une partie, utilisez <code>split()</code> (ou <code>rsplit()</code>, <code>lsplit()</code> pour travailler sur la droite ou la gauche de la chaîne) :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">&gt;&gt;&gt;</span> s = <span style="color: #483d8b;">&quot;&quot;&quot;Mais, vous savez, moi je ne crois pas qu'il y ait de bonne ou de mauvaise situation. Moi, si je devais résumer ma vie aujourd'hui avec vous, je dirais que c'est d'abord des rencontres, des gens qui m'ont tendu la main, peut-être à un moment où je ne pouvais pas, où j'étais seul chez moi. Et c'est assez curieux de se dire que les hasards, les rencontres forgent une destinée... Parce que quand on a le goût de la chose, quand on a le goût de la chose bien faite, le beau geste, parfois on ne trouve pas l'interlocuteur en face, je dirais, le miroir qui vous aide à avancer. Alors ce n'est pas mon cas, comme je le disais là, puisque moi au contraire, j'ai pu ; et je dis merci à la vie, je lui dis merci et je chante la vie, je danse la vie... Je ne suis qu'amour ! Et finalement, quand beaucoup de gens aujourd'hui me disent &quot;Mais comment fais-tu pour avoir cette humanité ?&quot;, et bien je leur réponds très simplement, je leur dis que c'est ce goût de l'amour, ce goût donc qui m'a poussé aujourd'hui à entreprendre une construction mécanique, mais demain, qui sait, peut-être simplement à me mettre au service de la communauté, à faire le don... le don de soi.&quot;&quot;&quot;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> s.<span style="color: black;">split</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
<span style="color: black;">&#91;</span>u<span style="color: #483d8b;">'Mais,'</span>, u<span style="color: #483d8b;">'vous'</span>, u<span style="color: #483d8b;">'savez,'</span>, u<span style="color: #483d8b;">'moi'</span>, u<span style="color: #483d8b;">'je'</span>, u<span style="color: #483d8b;">'ne'</span>, u<span style="color: #483d8b;">'crois'</span>, u<span style="color: #483d8b;">'pas'</span>, u<span style="color: #483d8b;">&quot;qu'il&quot;</span>, u<span style="color: #483d8b;">'y'</span>, u<span style="color: #483d8b;">'ait'</span>, u<span style="color: #483d8b;">'de'</span>, u<span style="color: #483d8b;">'bonne'</span>, u<span style="color: #483d8b;">'ou'</span>, u<span style="color: #483d8b;">'de'</span>, u<span style="color: #483d8b;">'mauvaise'</span>, u<span style="color: #483d8b;">'situation.'</span>, u<span style="color: #483d8b;">'Moi,'</span>, u<span style="color: #483d8b;">'si'</span>, u<span style="color: #483d8b;">'je'</span>, u<span style="color: #483d8b;">'devais'</span>, u<span style="color: #483d8b;">'r<span style="color: #000099; font-weight: bold;">\x</span>e9sumer'</span>, u<span style="color: #483d8b;">'ma'</span>, u<span style="color: #483d8b;">'vie'</span>, u<span style="color: #483d8b;">&quot;aujourd'hui&quot;</span>, u<span style="color: #483d8b;">'avec'</span>, u<span style="color: #483d8b;">'vous,'</span>, u<span style="color: #483d8b;">'je'</span>, u<span style="color: #483d8b;">'dirais'</span>, u<span style="color: #483d8b;">'que'</span>, u<span style="color: #483d8b;">&quot;c'est&quot;</span>, u<span style="color: #483d8b;">&quot;d'abord&quot;</span>, u<span style="color: #483d8b;">'des'</span>, u<span style="color: #483d8b;">'rencontres,'</span>, u<span style="color: #483d8b;">'des'</span>, u<span style="color: #483d8b;">'gens'</span>, u<span style="color: #483d8b;">'qui'</span>, u<span style="color: #483d8b;">&quot;m'ont&quot;</span>, u<span style="color: #483d8b;">'tendu'</span>, u<span style="color: #483d8b;">'la'</span>, u<span style="color: #483d8b;">'main,'</span>, u<span style="color: #483d8b;">'peut-<span style="color: #000099; font-weight: bold;">\x</span>eatre'</span>, u<span style="color: #483d8b;">'<span style="color: #000099; font-weight: bold;">\x</span>e0'</span>, u<span style="color: #483d8b;">'un'</span>, u<span style="color: #483d8b;">'moment'</span>, u<span style="color: #483d8b;">'o<span style="color: #000099; font-weight: bold;">\x</span>f9'</span>, u<span style="color: #483d8b;">'je'</span>, u<span style="color: #483d8b;">'ne'</span>, u<span style="color: #483d8b;">'pouvais'</span>, u<span style="color: #483d8b;">'pas,'</span>, u<span style="color: #483d8b;">'o<span style="color: #000099; font-weight: bold;">\x</span>f9'</span>, u<span style="color: #483d8b;">&quot;j'<span style="color: #000099; font-weight: bold;">\x</span>e9tais&quot;</span>, u<span style="color: #483d8b;">'seul'</span>, u<span style="color: #483d8b;">'chez'</span>, u<span style="color: #483d8b;">'moi.'</span>, u<span style="color: #483d8b;">'Et'</span>, u<span style="color: #483d8b;">&quot;c'est&quot;</span>, u<span style="color: #483d8b;">'assez'</span>, u<span style="color: #483d8b;">'curieux'</span>, u<span style="color: #483d8b;">'de'</span>, u<span style="color: #483d8b;">'se'</span>, u<span style="color: #483d8b;">'dire'</span>, u<span style="color: #483d8b;">'que'</span>, u<span style="color: #483d8b;">'les'</span>, u<span style="color: #483d8b;">'hasards,'</span>, u<span style="color: #483d8b;">'les'</span>, u<span style="color: #483d8b;">'rencontres'</span>, u<span style="color: #483d8b;">'forgent'</span>, u<span style="color: #483d8b;">'une'</span>, u<span style="color: #483d8b;">'destin<span style="color: #000099; font-weight: bold;">\x</span>e9e...'</span>, u<span style="color: #483d8b;">'Parce'</span>, u<span style="color: #483d8b;">'que'</span>, u<span style="color: #483d8b;">'quand'</span>, u<span style="color: #483d8b;">'on'</span>, u<span style="color: #483d8b;">'a'</span>, u<span style="color: #483d8b;">'le'</span>, u<span style="color: #483d8b;">'go<span style="color: #000099; font-weight: bold;">\x</span>fbt'</span>, u<span style="color: #483d8b;">'de'</span>, u<span style="color: #483d8b;">'la'</span>, u<span style="color: #483d8b;">'chose,'</span>, u<span style="color: #483d8b;">'quand'</span>, u<span style="color: #483d8b;">'on'</span>, u<span style="color: #483d8b;">'a'</span>, u<span style="color: #483d8b;">'le'</span>, u<span style="color: #483d8b;">'go<span style="color: #000099; font-weight: bold;">\x</span>fbt'</span>, u<span style="color: #483d8b;">'de'</span>, u<span style="color: #483d8b;">'la'</span>, u<span style="color: #483d8b;">'chose'</span>, u<span style="color: #483d8b;">'bien'</span>, u<span style="color: #483d8b;">'faite,'</span>, u<span style="color: #483d8b;">'le'</span>, u<span style="color: #483d8b;">'beau'</span>, u<span style="color: #483d8b;">'geste,'</span>, u<span style="color: #483d8b;">'parfois'</span>, u<span style="color: #483d8b;">'on'</span>, u<span style="color: #483d8b;">'ne'</span>, u<span style="color: #483d8b;">'trouve'</span>, u<span style="color: #483d8b;">'pas'</span>, u<span style="color: #483d8b;">&quot;l'interlocuteur&quot;</span>, u<span style="color: #483d8b;">'en'</span>, u<span style="color: #483d8b;">'face,'</span>, u<span style="color: #483d8b;">'je'</span>, u<span style="color: #483d8b;">'dirais,'</span>, u<span style="color: #483d8b;">'le'</span>, u<span style="color: #483d8b;">'miroir'</span>, u<span style="color: #483d8b;">'qui'</span>, u<span style="color: #483d8b;">'vous'</span>, u<span style="color: #483d8b;">'aide'</span>, u<span style="color: #483d8b;">'<span style="color: #000099; font-weight: bold;">\x</span>e0'</span>, u<span style="color: #483d8b;">'avancer.'</span>, u<span style="color: #483d8b;">'Alors'</span>, u<span style="color: #483d8b;">'ce'</span>, u<span style="color: #483d8b;">&quot;n'est&quot;</span>, u<span style="color: #483d8b;">'pas'</span>, u<span style="color: #483d8b;">'mon'</span>, u<span style="color: #483d8b;">'cas,'</span>, u<span style="color: #483d8b;">'comme'</span>, u<span style="color: #483d8b;">'je'</span>, u<span style="color: #483d8b;">'le'</span>, u<span style="color: #483d8b;">'disais'</span>, u<span style="color: #483d8b;">'l<span style="color: #000099; font-weight: bold;">\x</span>e0,'</span>, u<span style="color: #483d8b;">'puisque'</span>, u<span style="color: #483d8b;">'moi'</span>, u<span style="color: #483d8b;">'au'</span>, u<span style="color: #483d8b;">'contraire,'</span>, u<span style="color: #483d8b;">&quot;j'ai&quot;</span>, u<span style="color: #483d8b;">'pu'</span>, u<span style="color: #483d8b;">';'</span>, u<span style="color: #483d8b;">'et'</span>, u<span style="color: #483d8b;">'je'</span>, u<span style="color: #483d8b;">'dis'</span>, u<span style="color: #483d8b;">'merci'</span>, u<span style="color: #483d8b;">'<span style="color: #000099; font-weight: bold;">\x</span>e0'</span>, u<span style="color: #483d8b;">'la'</span>, u<span style="color: #483d8b;">'vie,'</span>, u<span style="color: #483d8b;">'je'</span>, u<span style="color: #483d8b;">'lui'</span>, u<span style="color: #483d8b;">'dis'</span>, u<span style="color: #483d8b;">'merci'</span>, u<span style="color: #483d8b;">'et'</span>, u<span style="color: #483d8b;">'je'</span>, u<span style="color: #483d8b;">'chante'</span>, u<span style="color: #483d8b;">'la'</span>, u<span style="color: #483d8b;">'vie,'</span>, u<span style="color: #483d8b;">'je'</span>, u<span style="color: #483d8b;">'danse'</span>, u<span style="color: #483d8b;">'la'</span>, u<span style="color: #483d8b;">'vie...'</span>, u<span style="color: #483d8b;">'Je'</span>, u<span style="color: #483d8b;">'ne'</span>, u<span style="color: #483d8b;">'suis'</span>, u<span style="color: #483d8b;">&quot;qu'amour&quot;</span>, u<span style="color: #483d8b;">'!'</span>, u<span style="color: #483d8b;">'Et'</span>, u<span style="color: #483d8b;">'finalement,'</span>, u<span style="color: #483d8b;">'quand'</span>, u<span style="color: #483d8b;">'beaucoup'</span>, u<span style="color: #483d8b;">'de'</span>, u<span style="color: #483d8b;">'gens'</span>, u<span style="color: #483d8b;">&quot;aujourd'hui&quot;</span>, u<span style="color: #483d8b;">'me'</span>, u<span style="color: #483d8b;">'disent'</span>, u<span style="color: #483d8b;">'&quot;Mais'</span>, u<span style="color: #483d8b;">'comment'</span>, u<span style="color: #483d8b;">'fais-tu'</span>, u<span style="color: #483d8b;">'pour'</span>, u<span style="color: #483d8b;">'avoir'</span>, u<span style="color: #483d8b;">'cette'</span>, u<span style="color: #483d8b;">'humanit<span style="color: #000099; font-weight: bold;">\x</span>e9'</span>, u<span style="color: #483d8b;">'?&quot;,'</span>, u<span style="color: #483d8b;">'et'</span>, u<span style="color: #483d8b;">'bien'</span>, u<span style="color: #483d8b;">'je'</span>, u<span style="color: #483d8b;">'leur'</span>, u<span style="color: #483d8b;">'r<span style="color: #000099; font-weight: bold;">\x</span>e9ponds'</span>, u<span style="color: #483d8b;">'tr<span style="color: #000099; font-weight: bold;">\x</span>e8s'</span>, u<span style="color: #483d8b;">'simplement,'</span>, u<span style="color: #483d8b;">'je'</span>, u<span style="color: #483d8b;">'leur'</span>, u<span style="color: #483d8b;">'dis'</span>, u<span style="color: #483d8b;">'que'</span>, u<span style="color: #483d8b;">&quot;c'est&quot;</span>, u<span style="color: #483d8b;">'ce'</span>, u<span style="color: #483d8b;">'go<span style="color: #000099; font-weight: bold;">\x</span>fbt'</span>, u<span style="color: #483d8b;">'de'</span>, u<span style="color: #483d8b;">&quot;l'amour,&quot;</span>, u<span style="color: #483d8b;">'ce'</span>, u<span style="color: #483d8b;">'go<span style="color: #000099; font-weight: bold;">\x</span>fbt'</span>, u<span style="color: #483d8b;">'donc'</span>, u<span style="color: #483d8b;">'qui'</span>, u<span style="color: #483d8b;">&quot;m'a&quot;</span>, u<span style="color: #483d8b;">'pouss<span style="color: #000099; font-weight: bold;">\x</span>e9'</span>, u<span style="color: #483d8b;">&quot;aujourd'hui&quot;</span>, u<span style="color: #483d8b;">'<span style="color: #000099; font-weight: bold;">\x</span>e0'</span>, u<span style="color: #483d8b;">'entreprendre'</span>, u<span style="color: #483d8b;">'une'</span>, u<span style="color: #483d8b;">'construction'</span>, u<span style="color: #483d8b;">'m<span style="color: #000099; font-weight: bold;">\x</span>e9canique,'</span>, u<span style="color: #483d8b;">'mais'</span>, u<span style="color: #483d8b;">'demain,'</span>, u<span style="color: #483d8b;">'qui'</span>, u<span style="color: #483d8b;">'sait,'</span>, u<span style="color: #483d8b;">'peut-<span style="color: #000099; font-weight: bold;">\x</span>eatre'</span>, u<span style="color: #483d8b;">'simplement'</span>, u<span style="color: #483d8b;">'<span style="color: #000099; font-weight: bold;">\x</span>e0'</span>, u<span style="color: #483d8b;">'me'</span>, u<span style="color: #483d8b;">'mettre'</span>, u<span style="color: #483d8b;">'au'</span>, u<span style="color: #483d8b;">'service'</span>, u<span style="color: #483d8b;">'de'</span>, u<span style="color: #483d8b;">'la'</span>, u<span style="color: #483d8b;">'communaut<span style="color: #000099; font-weight: bold;">\x</span>e9,'</span>, u<span style="color: #483d8b;">'<span style="color: #000099; font-weight: bold;">\x</span>e0'</span>, u<span style="color: #483d8b;">'faire'</span>, u<span style="color: #483d8b;">'le'</span>, u<span style="color: #483d8b;">'don...'</span>, u<span style="color: #483d8b;">'le'</span>, u<span style="color: #483d8b;">'don'</span>, u<span style="color: #483d8b;">'de'</span>, u<span style="color: #483d8b;">'soi.'</span><span style="color: black;">&#93;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> s.<span style="color: black;">split</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#93;</span>
u<span style="color: #483d8b;">'Mais,'</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> s.<span style="color: black;">split</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">5</span>:<span style="color: #ff4500;">7</span><span style="color: black;">&#93;</span>
<span style="color: black;">&#91;</span>u<span style="color: #483d8b;">'ne'</span>, u<span style="color: #483d8b;">'crois'</span><span style="color: black;">&#93;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> s.<span style="color: black;">split</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">','</span><span style="color: black;">&#41;</span>
<span style="color: black;">&#91;</span>u<span style="color: #483d8b;">'Mais'</span>, u<span style="color: #483d8b;">' vous savez'</span>, u<span style="color: #483d8b;">&quot; moi je ne crois pas qu'il y ait de bonne ou de mauvaise situation. Moi&quot;</span>, u<span style="color: #483d8b;">&quot; si je devais r<span style="color: #000099; font-weight: bold;">\x</span>e9sumer ma vie aujourd'hui avec vous&quot;</span>, u<span style="color: #483d8b;">&quot; je dirais que c'est d'abord des rencontres&quot;</span>, u<span style="color: #483d8b;">&quot; des gens qui m'ont tendu la main&quot;</span>, u<span style="color: #483d8b;">' peut-<span style="color: #000099; font-weight: bold;">\x</span>eatre <span style="color: #000099; font-weight: bold;">\x</span>e0 un moment o<span style="color: #000099; font-weight: bold;">\x</span>f9 je ne pouvais pas'</span>, u<span style="color: #483d8b;">&quot; o<span style="color: #000099; font-weight: bold;">\x</span>f9 j'<span style="color: #000099; font-weight: bold;">\x</span>e9tais seul chez moi. Et c'est assez curieux de se dire que les hasards&quot;</span>, u<span style="color: #483d8b;">' les rencontres forgent une destin<span style="color: #000099; font-weight: bold;">\x</span>e9e... Parce que quand on a le go<span style="color: #000099; font-weight: bold;">\x</span>fbt de la chose'</span>, u<span style="color: #483d8b;">' quand on a le go<span style="color: #000099; font-weight: bold;">\x</span>fbt de la chose bien faite'</span>, u<span style="color: #483d8b;">' le beau geste'</span>, u<span style="color: #483d8b;">&quot; parfois on ne trouve pas l'interlocuteur en face&quot;</span>, u<span style="color: #483d8b;">' je dirais'</span>, u<span style="color: #483d8b;">&quot; le miroir qui vous aide <span style="color: #000099; font-weight: bold;">\x</span>e0 avancer. Alors ce n'est pas mon cas&quot;</span>, u<span style="color: #483d8b;">' comme je le disais l<span style="color: #000099; font-weight: bold;">\x</span>e0'</span>, u<span style="color: #483d8b;">' puisque moi au contraire'</span>, u<span style="color: #483d8b;">&quot; j'ai pu ; et je dis merci <span style="color: #000099; font-weight: bold;">\x</span>e0 la vie&quot;</span>, u<span style="color: #483d8b;">' je lui dis merci et je chante la vie'</span>, u<span style="color: #483d8b;">&quot; je danse la vie... Je ne suis qu'amour ! Et finalement&quot;</span>, u<span style="color: #483d8b;">' quand beaucoup de gens aujourd<span style="color: #000099; font-weight: bold;">\'</span>hui me disent &quot;Mais comment fais-tu pour avoir cette humanit<span style="color: #000099; font-weight: bold;">\x</span>e9 ?&quot;'</span>, u<span style="color: #483d8b;">' et bien je leur r<span style="color: #000099; font-weight: bold;">\x</span>e9ponds tr<span style="color: #000099; font-weight: bold;">\x</span>e8s simplement'</span>, u<span style="color: #483d8b;">&quot; je leur dis que c'est ce go<span style="color: #000099; font-weight: bold;">\x</span>fbt de l'amour&quot;</span>, u<span style="color: #483d8b;">&quot; ce go<span style="color: #000099; font-weight: bold;">\x</span>fbt donc qui m'a pouss<span style="color: #000099; font-weight: bold;">\x</span>e9 aujourd'hui <span style="color: #000099; font-weight: bold;">\x</span>e0 entreprendre une construction m<span style="color: #000099; font-weight: bold;">\x</span>e9canique&quot;</span>, u<span style="color: #483d8b;">' mais demain'</span>, u<span style="color: #483d8b;">' qui sait'</span>, u<span style="color: #483d8b;">' peut-<span style="color: #000099; font-weight: bold;">\x</span>eatre simplement <span style="color: #000099; font-weight: bold;">\x</span>e0 me mettre au service de la communaut<span style="color: #000099; font-weight: bold;">\x</span>e9'</span>, u<span style="color: #483d8b;">' <span style="color: #000099; font-weight: bold;">\x</span>e0 faire le don... le don de soi.'</span><span style="color: black;">&#93;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> s.<span style="color: black;">split</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'.'</span><span style="color: black;">&#41;</span>
<span style="color: black;">&#91;</span>u<span style="color: #483d8b;">&quot;Mais, vous savez, moi je ne crois pas qu'il y ait de bonne ou de mauvaise situation&quot;</span>, u<span style="color: #483d8b;">&quot; Moi, si je devais r<span style="color: #000099; font-weight: bold;">\x</span>e9sumer ma vie aujourd'hui avec vous, je dirais que c'est d'abord des rencontres, des gens qui m'ont tendu la main, peut-<span style="color: #000099; font-weight: bold;">\x</span>eatre <span style="color: #000099; font-weight: bold;">\x</span>e0 un moment o<span style="color: #000099; font-weight: bold;">\x</span>f9 je ne pouvais pas, o<span style="color: #000099; font-weight: bold;">\x</span>f9 j'<span style="color: #000099; font-weight: bold;">\x</span>e9tais seul chez moi&quot;</span>, u<span style="color: #483d8b;">&quot; Et c'est assez curieux de se dire que les hasards, les rencontres forgent une destin<span style="color: #000099; font-weight: bold;">\x</span>e9e&quot;</span>, u<span style="color: #483d8b;">''</span>, u<span style="color: #483d8b;">''</span>, u<span style="color: #483d8b;">&quot; Parce que quand on a le go<span style="color: #000099; font-weight: bold;">\x</span>fbt de la chose, quand on a le go<span style="color: #000099; font-weight: bold;">\x</span>fbt de la chose bien faite, le beau geste, parfois on ne trouve pas l'interlocuteur en face, je dirais, le miroir qui vous aide <span style="color: #000099; font-weight: bold;">\x</span>e0 avancer&quot;</span>, u<span style="color: #483d8b;">&quot; Alors ce n'est pas mon cas, comme je le disais l<span style="color: #000099; font-weight: bold;">\x</span>e0, puisque moi au contraire, j'ai pu ; et je dis merci <span style="color: #000099; font-weight: bold;">\x</span>e0 la vie, je lui dis merci et je chante la vie, je danse la vie&quot;</span>, u<span style="color: #483d8b;">''</span>, u<span style="color: #483d8b;">''</span>, u<span style="color: #483d8b;">' Je ne suis qu<span style="color: #000099; font-weight: bold;">\'</span>amour ! Et finalement, quand beaucoup de gens aujourd<span style="color: #000099; font-weight: bold;">\'</span>hui me disent &quot;Mais comment fais-tu pour avoir cette humanit<span style="color: #000099; font-weight: bold;">\x</span>e9 ?&quot;, et bien je leur r<span style="color: #000099; font-weight: bold;">\x</span>e9ponds tr<span style="color: #000099; font-weight: bold;">\x</span>e8s simplement, je leur dis que c<span style="color: #000099; font-weight: bold;">\'</span>est ce go<span style="color: #000099; font-weight: bold;">\x</span>fbt de l<span style="color: #000099; font-weight: bold;">\'</span>amour, ce go<span style="color: #000099; font-weight: bold;">\x</span>fbt donc qui m<span style="color: #000099; font-weight: bold;">\'</span>a pouss<span style="color: #000099; font-weight: bold;">\x</span>e9 aujourd<span style="color: #000099; font-weight: bold;">\'</span>hui <span style="color: #000099; font-weight: bold;">\x</span>e0 entreprendre une construction m<span style="color: #000099; font-weight: bold;">\x</span>e9canique, mais demain, qui sait, peut-<span style="color: #000099; font-weight: bold;">\x</span>eatre simplement <span style="color: #000099; font-weight: bold;">\x</span>e0 me mettre au service de la communaut<span style="color: #000099; font-weight: bold;">\x</span>e9, <span style="color: #000099; font-weight: bold;">\x</span>e0 faire le don'</span>, u<span style="color: #483d8b;">''</span>, u<span style="color: #483d8b;">''</span>, u<span style="color: #483d8b;">' le don de soi'</span>, u<span style="color: #483d8b;">''</span><span style="color: black;">&#93;</span></pre></div></div>

<p>Et n&#8217;oubliez pas que vous pouvez appeler <code>join()</code> derrière.</p>
<p>Si vous devez altérer la chaîne, utilisez <code>strip()</code> (et <code>rstrip()</code>, <code>lstrip()</code>) ou <code>replace()</code> :</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;Les nouilles cuisent au jus de canne&quot;</span>.<span style="color: black;">replace</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'noui'</span>, <span style="color: #483d8b;">'coui'</span><span style="color: black;">&#41;</span>.<span style="color: black;">replace</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'cui'</span>, <span style="color: #483d8b;">'nui'</span><span style="color: black;">&#41;</span>.<span style="color: black;">replace</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'jus'</span>, <span style="color: #483d8b;">'cul'</span><span style="color: black;">&#41;</span>.<span style="color: black;">replace</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'canne'</span>, <span style="color: #483d8b;">'jeanne'</span><span style="color: black;">&#41;</span>
u<span style="color: #483d8b;">'Les couilles nuisent au cul de jeanne'</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #483d8b;">&quot;                               .                       &quot;</span>.<span style="color: black;">strip</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
u<span style="color: #483d8b;">'.'</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #483d8b;">&quot;===                               .                       ======&quot;</span>.<span style="color: black;">strip</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;= &quot;</span><span style="color: black;">&#41;</span>
u<span style="color: #483d8b;">'.'</span></pre></div></div>

<p>En plus, les chaînes sont itérables, indexables et sliceables, donc :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">&gt;&gt;&gt;</span> s = <span style="color: #483d8b;">&quot;&quot;&quot;And I will strike down upon thee with great vengeance and furious anger those who attempt to poison and destroy my brothers. And you will know my name is the Lord when I lay my vengeance upon you!&quot;&quot;&quot;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> s<span style="color: black;">&#91;</span><span style="color: #ff4500;">3</span>:<span style="color: #ff4500;">30</span>:<span style="color: #ff4500;">3</span><span style="color: black;">&#93;</span>
u<span style="color: #483d8b;">' wltkdnp '</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> s.<span style="color: black;">split</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
<span style="color: black;">&#91;</span>u<span style="color: #483d8b;">'And'</span>, u<span style="color: #483d8b;">'I'</span>, u<span style="color: #483d8b;">'will'</span>, u<span style="color: #483d8b;">'strike'</span>, u<span style="color: #483d8b;">'down'</span>, u<span style="color: #483d8b;">'upon'</span>, u<span style="color: #483d8b;">'thee'</span>, u<span style="color: #483d8b;">'with'</span>, u<span style="color: #483d8b;">'great'</span>, u<span style="color: #483d8b;">'vengeance'</span>, u<span style="color: #483d8b;">'and'</span>, u<span style="color: #483d8b;">'furious'</span>, u<span style="color: #483d8b;">'anger'</span>, u<span style="color: #483d8b;">'those'</span>, u<span style="color: #483d8b;">'who'</span>, u<span style="color: #483d8b;">'attempt'</span>, u<span style="color: #483d8b;">'to'</span>, u<span style="color: #483d8b;">'poison'</span>, u<span style="color: #483d8b;">'and'</span>, u<span style="color: #483d8b;">'destroy'</span>, u<span style="color: #483d8b;">'my'</span>, u<span style="color: #483d8b;">'brothers.'</span>, u<span style="color: #483d8b;">'And'</span>, u<span style="color: #483d8b;">'you'</span>, u<span style="color: #483d8b;">'will'</span>, u<span style="color: #483d8b;">'know'</span>, u<span style="color: #483d8b;">'my'</span>, u<span style="color: #483d8b;">'name'</span>, u<span style="color: #483d8b;">'is'</span>, u<span style="color: #483d8b;">'the'</span>, u<span style="color: #483d8b;">'Lord'</span>, u<span style="color: #483d8b;">'when'</span>, u<span style="color: #483d8b;">'I'</span>, u<span style="color: #483d8b;">'lay'</span>, u<span style="color: #483d8b;">'my'</span>, u<span style="color: #483d8b;">'vengeance'</span>, u<span style="color: #483d8b;">'upon'</span>, u<span style="color: #483d8b;">'you!'</span><span style="color: black;">&#93;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> s<span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#93;</span>
u<span style="color: #483d8b;">'A'</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #483d8b;">''</span>.<span style="color: black;">join</span><span style="color: black;">&#40;</span><span style="color: black;">&#91;</span><span style="color: black;">&#40;</span>l.<span style="color: black;">upper</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span> <span style="color: #ff7700;font-weight:bold;">if</span> i <span style="color: #66cc66;">%</span> <span style="color: #ff4500;">2</span> <span style="color: #ff7700;font-weight:bold;">else</span> l<span style="color: black;">&#41;</span> <span style="color: #ff7700;font-weight:bold;">for</span> i, l <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">enumerate</span><span style="color: black;">&#40;</span>s<span style="color: black;">&#41;</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span>
u<span style="color: #483d8b;">'ANd I wIlL StRiKe dOwN UpOn tHeE WiTh gReAt vEnGeAnCe aNd fUrIoUs aNgEr tHoSe wHo aTtEmPt tO PoIsOn aNd dEsTrOy mY BrOtHeRs. AnD YoU WiLl kNoW My nAmE Is tHe LOrD WhEn I lAy mY VeNgEaNcE UpOn yOu!'</span></pre></div></div>

<p>Bref, avant de sortir le bazooka, souvenez-vous que vous avez un arsenal déjà très approprié pour traiter les strings, dont les perfs seront en plus probablement meilleures.</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=7042&amp;md5=3535a823fe3ee3bc2897baa7909022f1" 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=7047
title: Django, une app à la fois : GET, POST et COOKIES
uri: Django-une-app-à-la-fois-GET-POST-et-COOKIES
url: http://sametmax.com/django-une-app-a-la-fois-get-post-et-cookies/
content:
<p>Nouvel ajout au projet <a href="http://sametmax.com/django-une-app-a-la-fois/">Django, une app à la fois</a>, qui démontre comment récupérer les valeurs passées en GET, POST et cookies. Avec en prime comment setter la valeur d&#8217;un cookie.</p>
<p>Pour une fois, ça n&#8217;a pas été trop long. En même temps il n&#8217;y avait qu&#8217;une vue à faire.</p>
<p>Chopez <a href="https://github.com/sametmax/Django--an-app-at-a-time">les sources</a> pendant que c&#8217;est encore chaud.</p>
<p>P.S: les corrections (bug, orthographe, esthétique&#8230;) sont toujours les bienvenues, même si c&#8217;est quelque chose de tout petit, sur la version anglaise comme la version française. N&#8217;hésitez pas à faire un Pull Request sur Github.</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=7047&amp;md5=9adf3a5734fbe70875b89546f9ca5b16" 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=6665
title: Allez vers les gens non cartésiens
uri: Allez-vers-les-gens-non-cartésiens
url: http://sametmax.com/allez-vers-les-gens-non-cartesiens-2/
content:
<p>En tant qu&#8217;informaticiens on aime la logique. On a aime l&#8217;esprit critique. On aime comprendre. On aime les explications. Et les comptes qui tombent rond (1024 étant un très beau chiffre rond).</p>
<p>J&#8217;ai une expérience différente : je baigne dans le monde de l&#8217;ésotérisme depuis tout petit, pour des raisons familiales.</p>
<p>J&#8217;ai passé 20 ans à m&#8217;énerver contre la stupidité de certains pratiques, contre l&#8217;illogisme de certains croyances, contre la faiblesse des nombreuses conférences, explications, démonstrations&#8230; J&#8217;ai beaucoup débattu, je me suis pas mal pris la tête. Je citais le Traité d&#8217;Athéologie et je montais sur mes grands chevaux dès la moindre attaque à la laïcité. J&#8217;étais plus anti-religieux que laïque, par ailleurs.</p>
<div id="attachment_6744" class="wp-caption aligncenter" style="width: 470px"><a href="media/538c6050.4uuI2.jpg" data-original-source="http://sametmax.com/wp-content/uploads/2013/07/4uuI2.jpg"><img src="media/538c6050.4uuI2.jpg" data-original-source="http://sametmax.com/wp-content/uploads/2013/07/4uuI2.jpg" alt="" title="Un peu de rigueur bande de bigots, ça vous tuerait ?" width="460" height="304" class="size-full wp-image-6744" /></a><p class="wp-caption-text">Un peu de rigueur bande de bigots, ça vous tuerait ?</p></div>
<p>Et puis un jour j&#8217;ai réalisé un truc.</p>
<p>Non, je n&#8217;ai pas trouvé la foi.</p>
<p>Mais vous savez, comme quand les fumeurs vous disent &#8220;j&#8217;ai arrêté, j&#8217;ai eu le déclic&#8221;.</p>
<p>Il y avait des tas de choses qui pouvaient améliorer ma vie dans leur monde.</p>
<p>Ça a été dur à avaler pour moi. Essayer des choses qui n&#8217;ont pas de sens, ou pire, qui sont expliquées par des sornettes. Ça a été très difficile d&#8217;accepter de tester des choses arbitrairement. Lire des textes de divers religions, fréquenter des gens de sectes, des illuminés, des &#8220;alternatifs&#8221;. Ou des gens comme Max :-)</p>
<p>Et c&#8217;est venu, j&#8217;ai compris que j&#8217;étais bien plus con qu&#8217;eux.</p>
<p>Comprenez bien, que ce soit les médecines parallèles, les diverses formes de pratiques spirituelles, le développement personnel, l&#8217;alchimie, les amateurs d&#8217;OVNI, de complots mondiaux et d&#8217;énergie infinie, les obsédés sexuels, les anarchistes et les drogués, j&#8217;ai tout rencontré.</p>
<p>Bon ok, pas tout, mais j&#8217;ai vraiment fais un sacré tour, et dans de nombreux endroits, parfois très exotiques.</p>
<p>Et j&#8217;aurais dû le faire plus tôt. J&#8217;aurais dû plus discuter avec des juifs, des islamiste, des chrétiens. J&#8217;aurais dû lire leurs textes.</p>
<p>Parce que comme toute les choses, il y a l&#8217;image qu&#8217;on s&#8217;en fait, et la réalité. Et il y a aussi les gens d&#8217;un côté, et les institutions de l&#8217;autre. Il y a les passionnés et les charlatans. C&#8217;est comme partout.</p>
<div id="attachment_6745" class="wp-caption aligncenter" style="width: 378px"><a href="media/9689538b.16de475c8dae340fe0227dbc59e41efd.jpg" data-original-source="http://sametmax.com/wp-content/uploads/2013/07/16de475c8dae340fe0227dbc59e41efd.jpg"><img src="media/9689538b.16de475c8dae340fe0227dbc59e41efd.jpg" data-original-source="http://sametmax.com/wp-content/uploads/2013/07/16de475c8dae340fe0227dbc59e41efd.jpg" alt="Caricature de la chapelle sixteen avec des bières et max donalds" title="Il y a plusieurs icones religieuses dans cette image, saurez-vous les reconnaître ?" width="368" height="244" class="size-full wp-image-6745" /></a><p class="wp-caption-text">Il y a plusieurs icones religieuses dans cette image, saurez-vous les reconnaître ?</p></div>
<p>Une fois qu&#8217;on a commencé à s&#8217;ouvrir un peu, on rencontre des tas de pratiques alimentaires, médicales, de rythmes de vie, de philosophies, de méthodes de résolution de problème, qui sont inspirantes.</p>
<p>Il n&#8217;y a pas besoin de croire en bouddha pour bénéficier de la méditation. Il n&#8217;y a pas besoin de croire en Allah pour bénéficier du soufisme. Il n&#8217;y a pas besoin de croire en la théorie de l&#8217;attraction pour bénéficier de la pensée positive. Il n&#8217;y a pas besoin de croire en l&#8217;au-delà ou en la réincarnation pour apprécier des textes sacrés. Il n&#8217;y a pas besoin de croire en Dieu pour réfléchir au concept. Il n&#8217;y a pas besoin de croire en la dernière théorie alimentaires pour se faire une cure.</p>
<p>Et tous les créationnismes ne sont pas des extrémistes incultes qui réfutent la science, croient en la bible et pensent que la Terre s&#8217;est faite en 7 jours.</p>
<p>Et toutes les spiritualités ne supposent pas une religion, rituels, prières, hiérarchie. Toute prière, rituelle, révérence n&#8217;a pas besoin d&#8217;un sens religieux.</p>
<p>Et toutes les sectes ne sont pas des prédateurs pour leurs membres. Tous les membres ne sont pas des faibles, des victimes, des exclus.</p>
<p>Et tous les témoins de miracles, d&#8217;ONVI et de phénomènes étranges ne sont pas des malades ou en manque d&#8217;attention.</p>
<p>Et tous les amateurs de théorie du complot ne sont pas des paranoïaques décervelés.</p>
<p>Comme souvent en fait, une grande partie est discrète, bienveillante, et possède des pistes de réflexions, de choix de vie, que je n&#8217;avais jamais envisagé.</p>
<p>J&#8217;ai passé des moments, mal à l&#8217;aise, au milieu de foules récitant des mantras. J&#8217;ai rencontré des gens qui se privaient de nourriture, d&#8217;autres qui disaient se nourrir en regardant le soleil. J&#8217;ai mangé avec des personnes riches, convaincues que les extra-terrestres gouvernaient le monde.</p>
<p>Je suis une meilleure personne depuis.</p>
<div id="attachment_6749" class="wp-caption aligncenter" style="width: 410px"><a href="media/d0a116e7.H6gkW.jpg" data-original-source="http://sametmax.com/wp-content/uploads/2013/07/H6gkW.jpg"><img src="media/d0a116e7.H6gkW.jpg" data-original-source="http://sametmax.com/wp-content/uploads/2013/07/H6gkW.jpg" alt="Photo de Jesus disant : &quot;les gars, ce n&#039;est pas ce que j&#039;ai dis&quot;" title="La plupart des prosélytes n&#039;ont jamais lu ou vérifié la source originale. Et la source originale n&#039;a de toute façon rien d&#039;originale." width="400" height="225" class="size-full wp-image-6749" /></a><p class="wp-caption-text">La plupart des prosélytes n&#039;ont jamais lu ou vérifié la source originale. Et la source originale n&#039;a de toute façon rien d&#039;originale.</p></div>
<p>J&#8217;ai gagné en culture, mais aussi en connaissance de moi-même. Je suis moins arrogant (et Max vous confirmera que j&#8217;ai encore du chemin ^^). J&#8217;ai bien entendu gagné en ouverture d&#8217;esprit. J&#8217;ai aussi découvert des pratiques avec des effets étonnant. Les explications sont diverses sur la cause de l&#8217;effet : placébo ? spirituel ? autre ? J&#8217;ai fini par réaliser que je m&#8217;en foutais complètement, pourvu que ça me serve.</p>
<p>J&#8217;ai beaucoup plus d&#8217;outils dans ma boîte à vie, certains que je n&#8217;aurais jamais osé imaginer ne serait-ce que regarder du coin de l’œil il y a quelques années. Ils sont là, sans raison, sans justification. Maintenant je fais des choses arbitrairement. Pas par foi, pas par compréhension, juste parce qu&#8217;<strong>un jour j&#8217;ai essayé, et ça m&#8217;a apporté</strong>.</p>
<p>En fait, nous faisons tous en permanence des choses arbitrairement. La plupart de nos décisions, passés à la loupe de la pensée critique, ne résistent pas très longtemps. Faisant ce constat, il est beaucoup plus facile d&#8217;accepter l&#8217;arbitraire d&#8217;autrui.</p>
<p>J&#8217;essaye donc maintenant compulsivement des choses.</p>
<p>J&#8217;ai eu des grains de riz collés à ma peau avec du sparadra pendant des jours.</p>
<p>J&#8217;ai avalé des mélanges de sel d&#8217;Epsom et d&#8217;huile d&#8217;olive.</p>
<p>J&#8217;ai récité des trucs chelou en langue Pali.</p>
<p>J&#8217;ai été tripoté par des magnétiseurs.</p>
<p>J&#8217;ai appelé les esprits.</p>
<p>Je suis resté des heures, immobile, en tailleur.</p>
<p>J&#8217;ai accompagné Max en Allemagne.</p>
<div id="attachment_6751" class="wp-caption aligncenter" style="width: 535px"><a href="media/7d42ed23.demotivational-posters-life-is-good.jpg" data-original-source="http://sametmax.com/wp-content/uploads/2013/07/demotivational-posters-life-is-good.jpg"><img src="media/7d42ed23.demotivational-posters-life-is-good.jpg" data-original-source="http://sametmax.com/wp-content/uploads/2013/07/demotivational-posters-life-is-good.jpg" alt="Photo de deux amis buvant une bière en se faisant sucer à bord d&#039;un bateau" title="L&#039;avantage de tester plein de choses, c&#039;est qu&#039;on a de bonnes surprises plus souvent que si on reste sur des rails." width="525" height="420" class="size-full wp-image-6751" /></a><p class="wp-caption-text">L&#039;avantage de tester plein de choses, c&#039;est qu&#039;on a de bonnes surprises plus souvent que si on reste sur des rails.</p></div>
<p>Il y a un énorme taux d&#8217;échecs, et de choses qui ne (ME?) servent à rien. A part comme hobby, car tester des choses nouvelles est encore une des activités les plus fun de la vie.</p>
<p>Mais finalement, pas plus que des choses considérées comme avérées par notre société. En fait, quand on essaye beaucoup de choses, étranges ou reconnues, le taux d&#8217;échec est toujours énorme. <strong>La réussite est même plutôt l&#8217;exception.</strong> C&#8217;est une bonne leçon de vie, et cela a déclenché une autre révélation importante.</p>
<p>Coluche disait : &#8220;ce n&#8217;est pas parce qu&#8217;ils sont nombreux à avoir tort qu&#8217;ils ont raison&#8221;.</p>
<p>À force de vérifier si des choses en lesquelles je ne croyais pas avait quelque chose à apporter, je me suis mis à vérifier si des choses en lesquelles je croyais dur comme fer avaient un sens.</p>
<p>Et c&#8217;est là la grande surprise. En fait, <strong>j&#8217;étais un croyant depuis le départ</strong>.</p>
<p>En effet, j&#8217;ai grandi en apprenant des milliers de choses parfaitement fausses (ou fluctuantes mais annoncées comme constantes). La société, la psychologie, la politique, l&#8217;alimentation, la santé, le travail, les interactions entre personnes, mais aussi la personne que je pensais être&#8230; Toute ces choses n&#8217;ont pas résisté au test.</p>
<p>Du coup j&#8217;ai fais le ménage, et à avoir commencé à fréquenter des gens qui croient, j&#8217;ai finis pas moins croire.</p>
<p>Et de plus en plus, <strong>la meilleure réponses que je trouve à dire, la plus honnête, quand je, ou on, me pose une question, c&#8217;est : &#8220;je ne sais pas&#8221;.</strong></p>
<p>Je ne suis toujours pas membre d&#8217;un secte ou d&#8217;un groupe religieux, mais j&#8217;ai bien des amis dans des groupes divers.</p>
<p>Je n&#8217;ai toujours pas de livre sacré ou de rituel, mais je ne méprise plus ceux qui en font une part importante de leur vie.</p>
<p>Plus que jamais, je crois qu&#8217;il faut tout mettre en doute, et vérifier par soi-même si on le peut, et en prime accepter qu&#8217;on a une grosse part d&#8217;arbitraire dans notre vie. Qu&#8217;<strong>on vit sur des &#8220;on-dit&#8221;</strong>. Que les institutions, l&#8217;histoire, la culture, la société et même le corps scientifique peuvent dire un énorme taux d’âneries. Que les voix parallèles peuvent parfois dire des choses essentielles. Qu&#8217;on va avoir tort soi-même, souvent, et que ce n&#8217;est pas si grave. Et surtout, que la majorité des gens ne savent pas ce qu&#8217;ils font, et n&#8217;ont aucune maîtrise de leur vie, y compris les personnes avec d&#8217;énormes responsabilités, dans tous les domaines.</p>
<div id="attachment_6754" class="wp-caption aligncenter" style="width: 380px"><a href="media/27417bf6.QHhjUZB.jpg" data-original-source="http://sametmax.com/wp-content/uploads/2013/07/QHhjUZB.jpg"><img src="media/27417bf6.QHhjUZB.jpg" data-original-source="http://sametmax.com/wp-content/uploads/2013/07/QHhjUZB.jpg" alt="Photo d&#039;une façade d&#039;immeuble pleine d&#039;antennes satellite" title="Si on fait la même chose que tout le monde, on obtient le même résultat que tout le monde. Le corolaire, c&#039;est que pour avoir un résultat différent, il faut donc commencer à agir différement." width="370" height="468" class="size-full wp-image-6754" /></a><p class="wp-caption-text">Si on fait la même chose que tout le monde, on obtient le même résultat que tout le monde. Le corolaire, c&#039;est que pour avoir un résultat différent, il faut donc commencer à agir différement.</p></div>
<p>La tolérance, c&#8217;est garder le respect pour une personne qui vous parle de &#8220;flux énergétique&#8221; sans avoir la moindre notion de ce qu&#8217;est de l&#8217;énergie. Parce que même si cela parait aberrant, il peut y avoir quelque chose d&#8217;utile à sa pratique.</p>
<p>L&#8217;ouverture d&#8217;esprit, c&#8217;est rester calme quand quelqu&#8217;un utilise la physique quantique ou le théorème de Gödel pour faire une démonstration fallacieuse qui justifie sa philosophie. Car son mode de vie peut être bénéfique malgré tout.</p>
<p>Le courage, c&#8217;est tenter ce que votre médecin vous interdit car c&#8217;est selon-lui très dangereux. Et quand ça marche au delà de tout espoir, de ne pas s&#8217;en vanter. Il reste la même personne qui vous a sauvé la vie, à 12 ans, en vous diagnostiquant une péritonite.</p>
<p>La générosité, c&#8217;est de répondre, encore et encore, simplement, inlassablement, aux mêmes questions des gens qui croisent votre route qui ont peur de tout cela, comme vous en avez eu peur un jour.</p>
<p>La persévérance c&#8217;est de ne pas s&#8217;arrêter aux échecs, au ridicule qui vous couvre quand vous réalisez qu&#8217;évidement, mettre une pierre dans votre nombril ne va rien faire du tout, vous vous attendiez à quoi ? C&#8217;est aussi continuer, et ce malgré les critiques des personnes moins ouvertes qui se demandent si vous n&#8217;êtes pas un peu bête, ou un peu fou. Et c&#8217;est accueillir la prochaine expérience avec moins de doute, même si elle parait complètement débile.</p>
<p>La diversité, c&#8217;est lire Alan Sokal ET Daniel Neal Walsch, Une Brève Histoire du Temps ET Les Quatres accords Toltèques, Think and Grow Rich ET Le Capital. Ils ne sont pas opposés, il sont complémentaires. Vous n&#8217;avez pas à en tirer ce que les autres veulent que vous en tiriez. Vous n&#8217;avez pas à l&#8217;utiliser tel que l&#8217;auteur veut que vous le fassiez. Vous n&#8217;avez pas à avoir le même avis que qui que ce soit sur la question. C&#8217;est votre expérience. Et seule l&#8217;expérience compte.</p>
<p>Malgré cela, et au final, la vie est courte, le monde est grand, et il vous faudra à un moment accepter la parole des autres. Vous n&#8217;allez pas construire un LHC perso pour vérifier ce qu&#8217;on dit sur le Boson, vous n&#8217;allez pas avaler une amanite phalloïde pour vous assurez que c&#8217;est bien vénéneux, et vous n&#8217;allez pas creuser chaque site archéologique pour confirmer que le dinosaure ont existé ailleurs que dans l&#8217;imagination de Spielberg.</p>
<div id="attachment_6760" class="wp-caption aligncenter" style="width: 247px"><a href="media/cf33eb22.kaa.png" data-original-source="http://sametmax.com/wp-content/uploads/2013/07/kaa.png"><img src="media/cf33eb22.kaa.png" data-original-source="http://sametmax.com/wp-content/uploads/2013/07/kaa.png" alt="Dessin de ka, le serpent du libre de la jungle" title="Rien à voir avec la choucroute, mais la version de &quot;Trust In Me&quot; de Selena Gomez est fantastique (https://www.youtube.com/watch?v=5v5Iulg5cVc)" width="237" height="176" class="size-full wp-image-6760" /></a><p class="wp-caption-text">Rien à voir avec la choucroute, mais la version de &quot;Trust In Me&quot; de Selena Gomez est fantastique (https://www.youtube.com/watch?v=5v5Iulg5cVc)</p></div>
<p><strong>A un moment il faut choisir de croire. Eh oui, même en science.</strong> Après la lecture des livres, la visite des musées, l&#8217;écoute des cours, il faut se décider. Pas parce que &#8220;tout le monde le dit&#8221;. Mais parce que ça vous parait crédible, c&#8217;est cohérent, il y a suffisamment de raisons de le croire, on pas suffisamment pour ne pas le croire. Ou tout simplement parce que ça vous arrange, après tout, qu&#8217;importe si on a eu tort, un fois dans un cercueil.</p>
<p>Il n&#8217;y a pas besoin de mysticisme ou de magie pour vivre. Mais plus encore, il faut se rappeler que <strong>rien n&#8217;est évident</strong>.</p>
<p>Ah oui, une dernière chose.</p>
<p>L&#8217;autre n&#8217;a pas forcément tort si vous avez raison.</p>
<p>Et si l&#8217;autre à tort, vous n&#8217;avez pas forcément raison.</p>
<p>P.S: j&#8217;ai volontairement choisi de ne pas parler des pratiques que j&#8217;ai incluses dans ma vie, ou rejetées, suite à ces expériences. L&#8217;article n&#8217;a pas pour but de vous dire ce que je pense être bon. L&#8217;article est là pour vous dire de trouver vous-même ce qui est bon pour vous. Et surtout de ne laisser personne d&#8217;autre, ni vos proches, ni la société, prendre la décision finale là dessus. <strong>Écoutez tout le monde, mais décidez seul.</strong></p>
<div id="attachment_6757" class="wp-caption aligncenter" style="width: 320px"><a href="media/36d4f86a.ipulations-photographiques-brillantes-qui-vous-feront-rever7.jpg" data-original-source="http://sametmax.com/wp-content/uploads/2013/07/28-manipulations-photographiques-brillantes-qui-vous-feront-rever7.jpg"><img src="media/36d4f86a.ipulations-photographiques-brillantes-qui-vous-feront-rever7.jpg" data-original-source="http://sametmax.com/wp-content/uploads/2013/07/28-manipulations-photographiques-brillantes-qui-vous-feront-rever7.jpg" alt="Photo montage d&#039;un homme qui tire une route comme un drap" title="Insérer ici vous-même une réfléxion profonde sur la destination, le chemin, bla bla bla." width="310" height="207" class="size-full wp-image-6757" /></a><p class="wp-caption-text">Insérer ici vous-même une réfléxion profonde sur la destination, le chemin, bla bla bla.</p></div>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=6665&amp;md5=081d883c90a8e1271155e2e5b16a6ff2" 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=7059
title: L’article du jour, tué par Kevin Spacey
uri: L-article-du-jour-tué-par-Kevin-Spacey
url: http://sametmax.com/larticle-du-jour-tue-par-kevin-spacey/
content:
<p>Désolé les gars, on m&#8217;a recommandé <a href="https://en.wikipedia.org/wiki/House_of_Cards_%28U.S._TV_series%29">House of Cards</a> qui joue la carte du combo Spacey en acteur, et Fincher derrière la caméra.</p>
<p>Ça m&#8217;a bouffé tout mon temps et j&#8217;ai rien écrit.</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=7059&amp;md5=5a400e2da2f4915c9d1bcf70e69dd94a" 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=7074
title: Merci Foxmask !
uri: Merci-Foxmask
url: http://sametmax.com/merci-foxmask/
content:
<p>Premier cadeau d&#8217;un lecteur. Snif. C&#8217;est trop choupinet.</p>
<div id="attachment_7075" class="wp-caption aligncenter" style="width: 418px"><a href="media/16cd4773.photo.jpg" data-original-source="http://sametmax.com/wp-content/uploads/2013/08/photo.jpg"><img src="media/16cd4773.photo.jpg" data-original-source="http://sametmax.com/wp-content/uploads/2013/08/photo.jpg" alt="Photo d&#039;un colis de ninich au caramel" title="Notre amie vient de nous le relayer, et Max ne l&#039;a pas encore vu, mais le tas a déjà diminué..." width="408" height="306" class="size-full wp-image-7075" /></a><p class="wp-caption-text">Notre amie vient de nous le relayer, et Max ne l&#039;a pas encore vu, mais le tas a déjà diminué...</p></div>
<p>C&#8217;est vraiment super agréable de pas avoir l&#8217;impression d&#8217;être tout seul derrière son écran :-)</p>
<p>Je tague l&#8217;article &#8220;niniches&#8221;, ça sera le tag unique du blog ^^</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=7074&amp;md5=66a2c13b85dca2927470306bc93e5d51" 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=7081
title: Un décorateur pour accepter les callbacks en Python
uri: Un-décorateur-pour-accepter-les-callbacks-en-Python
url: http://sametmax.com/un-decorateur-pour-accepter-les-callbacks-en-python/
content:
<p>Si vous lisez assidûment ce blog, et je n&#8217;en doute pas car il est génial, vous savez ce qu&#8217;est un <a href="http://sametmax.com/comprendre-les-decorateurs-python-pas-a-pas-partie-1/">décorateur</a> et un <a href="http://sametmax.com/quest-ce-quun-callback/">callback</a>. On a même vu comment<a href="http://sametmax.com/le-pattern-observer-en-utilisant-des-decorateurs/"> créer un système de gestion d&#8217;événements</a> en utilisant ces deux concepts.</p>
<p>Un des événements auxquels on veut réagir le plus souvent, c&#8217;est l&#8217;appel d&#8217;une fonction, donc en gros être capable de fournir un callback quand une fonction est appelée. On peut bien entendu coder la logique du callback dans chaque fonction et méthode que l&#8217;on met en œuvre, mais avec un peu d&#8217;astuce, on peut trouver une solution générique qui va couvrir Pareto des besoins.</p>
<p>L&#8217;idée, c&#8217;est donc de coder un décorateur :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">def</span> accept_callbacks<span style="color: black;">&#40;</span>func<span style="color: black;">&#41;</span>:
&nbsp;
    <span style="color: #808080; font-style: italic;"># on va stocker tous les callbacks là dedans</span>
    callbacks = <span style="color: black;">&#91;</span><span style="color: black;">&#93;</span>
&nbsp;
    @wraps<span style="color: black;">&#40;</span>func<span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">def</span> wrapper<span style="color: black;">&#40;</span><span style="color: #66cc66;">*</span>args, <span style="color: #66cc66;">**</span>kwargs<span style="color: black;">&#41;</span>:
&nbsp;
        <span style="color: #808080; font-style: italic;"># on appelle la fonction originale</span>
        result = func<span style="color: black;">&#40;</span><span style="color: #66cc66;">*</span>args, <span style="color: #66cc66;">**</span>kwargs<span style="color: black;">&#41;</span>
&nbsp;
        <span style="color: #808080; font-style: italic;"># on appelle ensuite chaque callback en lui passant le resultat </span>
        <span style="color: #808080; font-style: italic;"># de la fonction ainsi que les paramètres qui avaient été passés</span>
        <span style="color: #ff7700;font-weight:bold;">for</span> callback <span style="color: #ff7700;font-weight:bold;">in</span> callbacks:
            callback<span style="color: black;">&#40;</span>result, <span style="color: #66cc66;">*</span>args, <span style="color: #66cc66;">**</span>kwargs<span style="color: black;">&#41;</span>
&nbsp;
        <span style="color: #808080; font-style: italic;"># et on retourne le résultat</span>
        <span style="color: #ff7700;font-weight:bold;">return</span> result
&nbsp;
    <span style="color: #808080; font-style: italic;"># on attache la liste des callbacks au wrapper pour y avoir accès depuis</span>
    <span style="color: #808080; font-style: italic;"># l'extérieur</span>
    wrapper.<span style="color: black;">callbacks</span> = callbacks
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">return</span> wrapper</pre></div></div>

<p>Du coup, pour accepter des callbacks sur une fonction, il suffit de décorer la fonction :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">@accept_callbacks
<span style="color: #ff7700;font-weight:bold;">def</span> add<span style="color: black;">&#40;</span>a, b<span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">return</span> a + b</pre></div></div>

<p>Ensuite on écrit son callback avec la signature qui va bien :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">def</span> mon_callback<span style="color: black;">&#40;</span>result, a, b<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;Ma fonction a été appelée avec a=%s et b=%s !&quot;</span> <span style="color: #66cc66;">%</span> <span style="color: black;">&#40;</span>a, b<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;Elle a retourné le résultat '%s'&quot;</span> <span style="color: #66cc66;">%</span> result<span style="color: black;">&#41;</span></pre></div></div>

<p>Et pour ajouter un callback, c&#8217;est juste une insertion dans la liste :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">add.<span style="color: black;">callbacks</span>.<span style="color: black;">append</span><span style="color: black;">&#40;</span>mon_callback<span style="color: black;">&#41;</span></pre></div></div>

<p>Derrière, chaque appel de la fonction va appeler également tous les callbacks :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span>add<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: #808080; font-style: italic;">## Ma fonction a été appelée avec a=1 et b=1 !</span>
<span style="color: #808080; font-style: italic;">## Elle a retourné le résultat '2'</span>
<span style="color: #808080; font-style: italic;">## 2</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span>add<span style="color: black;">&#40;</span><span style="color: #ff4500;">42</span>, <span style="color: #ff4500;">69</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
<span style="color: #808080; font-style: italic;">## Ma fonction a été appelée avec a=42 et b=69 !</span>
<span style="color: #808080; font-style: italic;">## Elle a retourné le résultat '111'</span>
<span style="color: #808080; font-style: italic;">## 111</span>
&nbsp;
add.<span style="color: black;">callbacks</span>.<span style="color: black;">remove</span><span style="color: black;">&#40;</span>mon_callback<span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span>add<span style="color: black;">&#40;</span><span style="color: #ff4500;">0</span>, <span style="color: #ff4500;">0</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
<span style="color: #808080; font-style: italic;"># 0</span></pre></div></div>

<p>Et le plus fun, c&#8217;est que ça marche aussi sans rien modifier avec les méthodes :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">def</span> autre_callback<span style="color: black;">&#40;</span>result, <span style="color: #008000;">self</span>, truc_important<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;Ma fonction a été appelée avec truc_important=%s !&quot;</span> <span style="color: #66cc66;">%</span> truc_important<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;Elle a retourné '%s'&quot;</span> <span style="color: #66cc66;">%</span> result<span style="color: black;">&#41;</span>
&nbsp;
&nbsp;
<span style="color: #ff7700;font-weight:bold;">class</span> CaMarcheAussiAvecUneClass<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>, repeat=<span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span>:
        <span style="color: #008000;">self</span>.<span style="color: black;">repeat</span> = repeat
&nbsp;
    @accept_callbacks
    <span style="color: #ff7700;font-weight:bold;">def</span> puisque_une_classe_a_des_methodes<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, truc_important<span style="color: black;">&#41;</span>:
        <span style="color: #ff7700;font-weight:bold;">return</span> truc_important.<span style="color: black;">upper</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span> <span style="color: #66cc66;">*</span> <span style="color: #008000;">self</span>.<span style="color: black;">repeat</span>
&nbsp;
&nbsp;
CaMarcheAussiAvecUneClass.<span style="color: black;">puisque_une_classe_a_des_methodes</span>.<span style="color: black;">callbacks</span>.<span style="color: black;">append</span><span style="color: black;">&#40;</span>autre_callback<span style="color: black;">&#41;</span>
&nbsp;
instance1 = CaMarcheAussiAvecUneClass<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
instance2 = CaMarcheAussiAvecUneClass<span style="color: black;">&#40;</span><span style="color: #ff4500;">2</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span>instance1.<span style="color: black;">puisque_une_classe_a_des_methodes</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;Le fromage de chèvre&quot;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
<span style="color: #808080; font-style: italic;">## Ma fonction a été appelée avec truc_important=Le fromage de chèvre !</span>
<span style="color: #808080; font-style: italic;">## Elle a retourné 'LE FROMAGE DE CHÈVRE'</span>
<span style="color: #808080; font-style: italic;">## LE FROMAGE DE CHÈVRE</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span>instance2.<span style="color: black;">puisque_une_classe_a_des_methodes</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;Les perforeuses&quot;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
<span style="color: #808080; font-style: italic;">## Ma fonction a été appelée avec truc_important=Les perforeuses !</span>
<span style="color: #808080; font-style: italic;">## Elle a retourné 'LES PERFOREUSESLES PERFOREUSES'</span>
<span style="color: #808080; font-style: italic;">## LES PERFOREUSESLES PERFOREUSES</span></pre></div></div>

<p>Par contre, si on veut qu&#8217;un callback ne s&#8217;active que pour une instance donnée, alors il faut ruser un peu :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #808080; font-style: italic;"># le retrait d'un callback, c'est un simple retrait de la liste</span>
CaMarcheAussiAvecUneClass.<span style="color: black;">puisque_une_classe_a_des_methodes</span>.<span style="color: black;">callbacks</span>.<span style="color: black;">remove</span><span style="color: black;">&#40;</span>autre_callback<span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> callback_pour_une_instance<span style="color: black;">&#40;</span>result, <span style="color: #008000;">self</span>, truc_important<span style="color: black;">&#41;</span>:
    <span style="color: #808080; font-style: italic;"># on check que l'instance est celle que l'on veut</span>
    <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #008000;">self</span> <span style="color: #ff7700;font-weight:bold;">is</span> instance1:
        <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;Ma fonction a été appelée avec truc_important=%s !&quot;</span> <span style="color: #66cc66;">%</span> truc_important<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;Elle a retourné '%s'&quot;</span> <span style="color: #66cc66;">%</span> result<span style="color: black;">&#41;</span>
&nbsp;
CaMarcheAussiAvecUneClass.<span style="color: black;">puisque_une_classe_a_des_methodes</span>.<span style="color: black;">callbacks</span>.<span style="color: black;">append</span><span style="color: black;">&#40;</span>callback_pour_une_instance<span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span>instance1.<span style="color: black;">puisque_une_classe_a_des_methodes</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;Les points noirs des coccinelles&quot;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
<span style="color: #808080; font-style: italic;">## Ma fonction a été appelée avec truc_important=Les points noirs des coccinelles !</span>
<span style="color: #808080; font-style: italic;">## Elle a retourné 'LES POINTS NOIRS DES COCCINELLES'</span>
<span style="color: #808080; font-style: italic;">## LES POINTS NOIRS DES COCCINELLES</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span>instance2.<span style="color: black;">puisque_une_classe_a_des_methodes</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;Les panneaux sens uniques&quot;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
<span style="color: #808080; font-style: italic;">## LES PANNEAUX SENS UNIQUESLES PANNEAUX SENS UNIQUES</span></pre></div></div>

<p>Niveau perf, ce n&#8217;est pas optimal, et bien sûr, l&#8217;appel des callbacks est synchrone et blocant. Ce n&#8217;est pas un souci dans 90 % des cas, pour les autres cas, vous devrez faire le truc à la main. En même temps, dès qu&#8217;on a des problèmes de perf, les codes génériques fonctionnent rarement.</p>
<p>Je vais peut être rajouter ça dans <a href="sametmax.com/batbelt-la-lib-des-petits-outils-python-qui-vont-bien/">batbelt</a> moi&#8230;</p>
<hr />
<p><a href="https://github.com/sametmax/codes-des-articles/blob/master/2013/aout/accept_callbacks.py">Télécharger le code de l&#8217;article</a></p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=7081&amp;md5=f0a11fb27c97ee69bcf6c900cff73371" 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=4559
title: Déshabillez-vous pour l’occasion
uri: Déshabillez-vous-pour-l-occasion
url: http://sametmax.com/deshabillez-vous-pour-loccasion/
content:
<p>Se marrer avec le cul, c&#8217;est pas juste faire ça, dans sa chambre à deux sous la couette.</p>
<p>C&#8217;est se faire sucer dans un train parce que votre copine veut voir si elle à le temps de vous faire venir avant que le contrôleur passe.</p>
<p>C&#8217;est s&#8217;habiller en cuir SM et se faire chevaucher par sa colloc qui vous fouette avec une ceinture, juste pour voir la gueule du livreur de pizza halluciné quand vous lui ouvrez la porte avec la mise en scène (prendre le billet à 4 pattes entre les dents fait son petit effet).</p>
<p>C&#8217;est se foutre à poil avec un bonnet de Père Noël pour faire la bises aux 50 invités pakistanais de la house party de votre BFF anglaise parce qu&#8217;hier, bourré et voulant impressionner son pote sosie de Jim Morisson, vous lui aviez dit que &#8220;cap&#8221;.</p>
<p>Max fait des soirées mousse dans les camps nudistes, pas pour la baise (enfin si un peu), mais parce que c&#8217;est fun.</p>
<p>Je connais une meuf qui se met à genou pour servir de table à oualpé pas pour se faire baiser (il ne lui arrive rien), mais pour le fun.</p>
<p>D&#8217;ailleurs j&#8217;écris ce post à poil, parce qu&#8217;il est 15 h et que pour coder je n&#8217;ai pas besoin de vêtements.</p>
<p>Si ce n&#8217;est pas reproductif, c&#8217;est récréatif. Marrez-vous.</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=4559&amp;md5=7cc7631e9a296e05cfd321c3d2d4e443" 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=7103
title: Éviter que Sublime Text n’écrase les parenthèses fermantes
uri: Éviter-que-Sublime-Text-n-écrase-les-parenthèses-fermantes
url: http://sametmax.com/eviter-que-sublime-text-necrase-les-parentheses-fermantes/
content:
<p><div class='one_third last'>
					
				</div><div class='clear'></div>Quand on tape une parenthèse fermante (ou <code>]</code> voire <code>}</code>) juste à côté d&#8217;une AUTRE parenthèse fermante, le comportement de Sublime Text par défaut est de ne pas ajouter de parenthèse, mais d&#8217;avancer d&#8217;un caractère.</p>
<p>La raison est que Sublime ferme automatiquement toute parenthèse ouverte, cette fonctionnalité est donc là pour vous éviter de taper une parenthèse fermante de trop.</p>
<p>Je déteste cette fonctionnalité.</p>
<p>Je suis assez grand pour savoir quand insérer ma parenthèse ou non, et je n&#8217;ai pas Parkinson. </p>
<p>Heureusement, comme tout dans cet éditeur qu&#8217;il est merveilleux, c&#8217;est désactivable. Ouvrez &#8220;Preferences > Key Bindings &#8211; User&#8221; et ajoutez ceci à la configuration :</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;">    <span style="color: #009900;">&#123;</span> <span style="color: #3366CC;">&quot;keys&quot;</span><span style="color: #339933;">:</span> <span style="color: #009900;">&#91;</span><span style="color: #3366CC;">&quot;<span style="color: #000099; font-weight: bold;">\&quot;</span>&quot;</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">&quot;command&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;insert&quot;</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">&quot;args&quot;</span><span style="color: #339933;">:</span> <span style="color: #009900;">&#123;</span><span style="color: #3366CC;">&quot;characters&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;<span style="color: #000099; font-weight: bold;">\&quot;</span>&quot;</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">&quot;context&quot;</span><span style="color: #339933;">:</span>
        <span style="color: #009900;">&#91;</span>
            <span style="color: #009900;">&#123;</span> <span style="color: #3366CC;">&quot;key&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;setting.auto_match_enabled&quot;</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">&quot;operator&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;equal&quot;</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">&quot;operand&quot;</span><span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">true</span> <span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span>
            <span style="color: #009900;">&#123;</span> <span style="color: #3366CC;">&quot;key&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;selection_empty&quot;</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">&quot;operator&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;equal&quot;</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">&quot;operand&quot;</span><span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">true</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">&quot;match_all&quot;</span><span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">true</span> <span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span>
            <span style="color: #009900;">&#123;</span> <span style="color: #3366CC;">&quot;key&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;following_text&quot;</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">&quot;operator&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;regex_contains&quot;</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">&quot;operand&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;^<span style="color: #000099; font-weight: bold;">\&quot;</span>&quot;</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">&quot;match_all&quot;</span><span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">true</span> <span style="color: #009900;">&#125;</span>
        <span style="color: #009900;">&#93;</span>
    <span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span>
    <span style="color: #009900;">&#123;</span> <span style="color: #3366CC;">&quot;keys&quot;</span><span style="color: #339933;">:</span> <span style="color: #009900;">&#91;</span><span style="color: #3366CC;">&quot;)&quot;</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">&quot;command&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;insert&quot;</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">&quot;args&quot;</span><span style="color: #339933;">:</span> <span style="color: #009900;">&#123;</span><span style="color: #3366CC;">&quot;characters&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;)&quot;</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">&quot;context&quot;</span><span style="color: #339933;">:</span>
        <span style="color: #009900;">&#91;</span>
            <span style="color: #009900;">&#123;</span> <span style="color: #3366CC;">&quot;key&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;setting.auto_match_enabled&quot;</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">&quot;operator&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;equal&quot;</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">&quot;operand&quot;</span><span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">true</span> <span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span>
            <span style="color: #009900;">&#123;</span> <span style="color: #3366CC;">&quot;key&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;selection_empty&quot;</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">&quot;operator&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;equal&quot;</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">&quot;operand&quot;</span><span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">true</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">&quot;match_all&quot;</span><span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">true</span> <span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span>
            <span style="color: #009900;">&#123;</span> <span style="color: #3366CC;">&quot;key&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;following_text&quot;</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">&quot;operator&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;regex_contains&quot;</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">&quot;operand&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;^<span style="color: #000099; font-weight: bold;">\\</span>)&quot;</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">&quot;match_all&quot;</span><span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">true</span> <span style="color: #009900;">&#125;</span>
        <span style="color: #009900;">&#93;</span>
    <span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span>
    <span style="color: #009900;">&#123;</span> <span style="color: #3366CC;">&quot;keys&quot;</span><span style="color: #339933;">:</span> <span style="color: #009900;">&#91;</span><span style="color: #3366CC;">&quot;'&quot;</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">&quot;command&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;insert&quot;</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">&quot;args&quot;</span><span style="color: #339933;">:</span> <span style="color: #009900;">&#123;</span><span style="color: #3366CC;">&quot;characters&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;'&quot;</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">&quot;context&quot;</span><span style="color: #339933;">:</span>
        <span style="color: #009900;">&#91;</span>
            <span style="color: #009900;">&#123;</span> <span style="color: #3366CC;">&quot;key&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;setting.auto_match_enabled&quot;</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">&quot;operator&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;equal&quot;</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">&quot;operand&quot;</span><span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">true</span> <span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span>
            <span style="color: #009900;">&#123;</span> <span style="color: #3366CC;">&quot;key&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;selection_empty&quot;</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">&quot;operator&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;equal&quot;</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">&quot;operand&quot;</span><span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">true</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">&quot;match_all&quot;</span><span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">true</span> <span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span>
            <span style="color: #009900;">&#123;</span> <span style="color: #3366CC;">&quot;key&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;following_text&quot;</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">&quot;operator&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;regex_contains&quot;</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">&quot;operand&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;^'&quot;</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">&quot;match_all&quot;</span><span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">true</span> <span style="color: #009900;">&#125;</span>
        <span style="color: #009900;">&#93;</span>
    <span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span>
    <span style="color: #009900;">&#123;</span> <span style="color: #3366CC;">&quot;keys&quot;</span><span style="color: #339933;">:</span> <span style="color: #009900;">&#91;</span><span style="color: #3366CC;">&quot;]&quot;</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span><span style="color: #3366CC;">&quot;command&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;insert&quot;</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">&quot;args&quot;</span><span style="color: #339933;">:</span> <span style="color: #009900;">&#123;</span><span style="color: #3366CC;">&quot;characters&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;]&quot;</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">&quot;context&quot;</span><span style="color: #339933;">:</span>
        <span style="color: #009900;">&#91;</span>
            <span style="color: #009900;">&#123;</span> <span style="color: #3366CC;">&quot;key&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;setting.auto_match_enabled&quot;</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">&quot;operator&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;equal&quot;</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">&quot;operand&quot;</span><span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">true</span> <span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span>
            <span style="color: #009900;">&#123;</span> <span style="color: #3366CC;">&quot;key&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;selection_empty&quot;</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">&quot;operator&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;equal&quot;</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">&quot;operand&quot;</span><span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">true</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">&quot;match_all&quot;</span><span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">true</span> <span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span>
            <span style="color: #009900;">&#123;</span> <span style="color: #3366CC;">&quot;key&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;following_text&quot;</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">&quot;operator&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;regex_contains&quot;</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">&quot;operand&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;^<span style="color: #000099; font-weight: bold;">\\</span>]&quot;</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">&quot;match_all&quot;</span><span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">true</span> <span style="color: #009900;">&#125;</span>
        <span style="color: #009900;">&#93;</span>
    <span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span>
    <span style="color: #009900;">&#123;</span> <span style="color: #3366CC;">&quot;keys&quot;</span><span style="color: #339933;">:</span> <span style="color: #009900;">&#91;</span><span style="color: #3366CC;">&quot;}&quot;</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">&quot;command&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;insert&quot;</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">&quot;args&quot;</span><span style="color: #339933;">:</span> <span style="color: #009900;">&#123;</span><span style="color: #3366CC;">&quot;characters&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;}&quot;</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">&quot;context&quot;</span><span style="color: #339933;">:</span>
        <span style="color: #009900;">&#91;</span>
            <span style="color: #009900;">&#123;</span> <span style="color: #3366CC;">&quot;key&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;setting.auto_match_enabled&quot;</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">&quot;operator&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;equal&quot;</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">&quot;operand&quot;</span><span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">true</span> <span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span>
            <span style="color: #009900;">&#123;</span> <span style="color: #3366CC;">&quot;key&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;selection_empty&quot;</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">&quot;operator&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;equal&quot;</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">&quot;operand&quot;</span><span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">true</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">&quot;match_all&quot;</span><span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">true</span> <span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span>
            <span style="color: #009900;">&#123;</span> <span style="color: #3366CC;">&quot;key&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;following_text&quot;</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">&quot;operator&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;regex_contains&quot;</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">&quot;operand&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;^<span style="color: #000099; font-weight: bold;">\\</span>}&quot;</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">&quot;match_all&quot;</span><span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">true</span> <span style="color: #009900;">&#125;</span>
        <span style="color: #009900;">&#93;</span>
    <span style="color: #009900;">&#125;</span></pre></div></div>

<p>Abracadabra !</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=7103&amp;md5=42734a1ea5b498b5e4ea6cd52bfae6bf" 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=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’affranchir des doublons d’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’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’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’est l’histoire d’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’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>


