Derniers messages sur Zeste de Savoirhttps://zestedesavoir.com/forums/2020-02-23T03:24:33+01:00Les derniers messages parus sur le forum de Zeste de Savoir.[Python] Multiplexage avec le module select, message #2161112020-02-23T03:24:33+01:00buffalo974/@buffalo974https://zestedesavoir.com/forums/sujet/13640/python-multiplexage-avec-le-module-select/?page=1#p216111<p>merci !</p>[Python] Multiplexage avec le module select, message #2159822020-02-20T09:37:25+01:00entwanne/@entwannehttps://zestedesavoir.com/forums/sujet/13640/python-multiplexage-avec-le-module-select/?page=1#p215982<figure><blockquote>
<p>Pour utiliser un chaque cœur d’un processeur multi-cœur, il faut soit lancer plusieurs programmes au niveau du système d’exploitation, soit <strong>lancer plusieurs threads au niveau d’un même programme</strong>.</p>
</blockquote><figcaption><a href="https://zestedesavoir.com/forums/sujet/13640/python-multiplexage-avec-le-module-select/?page=1#p215980">r0anne</a></figcaption></figure>
<p>À relativiser cependant en Python, puisqu’actuellement avec le <em><abbr title="Global Interpreter Lock">GIL</abbr></em> même si deux <em>threads</em> s’exécutent sur deux cœurs différents, ils ne le feront jamais simultanément.</p>[Python] Multiplexage avec le module select, message #2159802020-02-20T08:51:44+01:00r0anne/@r0annehttps://zestedesavoir.com/forums/sujet/13640/python-multiplexage-avec-le-module-select/?page=1#p215980<p>Salut,</p>
<p>À l’origine, il y a longtemps, les microprocesseurs disposaient d’un seul cœur, donc d’un seul « fil d’exécution » : un seul thread au niveau matériel. Les instructions étaient exécutées les unes après les autres :</p>
<div class="hljs-code-div"><div class="hljs-line-numbers"><span></span><span></span></div><pre><code class="hljs language-coq">| <span class="hljs-type">Instruction</span> <span class="hljs-number">1</span> | <span class="hljs-type">Instruction</span> <span class="hljs-number">2</span> | <span class="hljs-type">Instruction</span> <span class="hljs-number">3</span> | <span class="hljs-type">... |
======> Temps</span> ======>
</code></pre></div>
<p>Par la suite, et pour monter en performances plus facilement qu’en miniaturisant et rendant toujours plus puissants les microprocesseurs, on a décidé de mettre plusieurs microprocesseurs logiques les uns à côté des autres : c’est l’avènement du « multi-cœur ».</p>
<div class="hljs-code-div"><div class="hljs-line-numbers"><span></span><span></span><span></span><span></span></div><pre><code class="hljs language-gherkin"> /\
Cœurs ||<span class="hljs-string"> </span>|<span class="hljs-string"> Instruction 1 </span>|<span class="hljs-string"> Instruction 2 </span>|<span class="hljs-string"> Instruction 3 </span>|<span class="hljs-string"> ... </span>|
||<span class="hljs-string"> </span>|<span class="hljs-string"> Instruction 4 </span>|<span class="hljs-string"> Instruction 5 </span>|<span class="hljs-string"> Instruction 6 </span>|<span class="hljs-string"> ... </span>|
======> Temps ======>
</code></pre></div>
<p>Pour utiliser un chaque cœur d’un processeur multi-cœur, il faut soit lancer plusieurs programmes au niveau du système d’exploitation, soit <strong>lancer plusieurs threads au niveau d’un même programme</strong>.</p>
<p>Maintenant, imaginons que je veuille que mon programme écoute sur 10 sockets différentes. Logiquement, écouter sur un socket va bloquer mon programme, ou du moins 10 threads.</p>
<p>Si j’exécute plusieurs programmes et que mon système d’exploitation est multi-tâches, alors il va mutualiser le fil d’exécution du CPU entre différents programmes (si j’ai plus de programmes en exécution que de cœurs) :</p>
<div class="hljs-code-div"><div class="hljs-line-numbers"><span></span><span></span></div><pre><code class="hljs language-coq">| <span class="hljs-type">Instruction</span> <span class="hljs-number">1</span> programme A | <span class="hljs-type">Instruction</span> <span class="hljs-number">1</span> programme B | <span class="hljs-type">Instruction</span> <span class="hljs-number">2</span> programme A | <span class="hljs-type">... |
======> Temps</span> ======>
</code></pre></div>
<p>Il en est de même si j’ai différents threads (et que j’ai plus de threads en activité que de cœurs) :</p>
<div class="hljs-code-div"><div class="hljs-line-numbers"><span></span><span></span></div><pre><code class="hljs language-coq">| <span class="hljs-type">Instruction</span> <span class="hljs-number">1</span> thread A | <span class="hljs-type">Instruction</span> <span class="hljs-number">1</span> thread B | <span class="hljs-type">Instruction</span> <span class="hljs-number">2</span> thread B | <span class="hljs-type">... |
======> Temps</span> ======>
</code></pre></div>
<p>Maintenant, utiliser des threads a des inconvénients :</p>
<ul>
<li>
<p>Tu peux faire communiquer des threads entre eux, mais c’est compliqué. Ils risquent de se marcher sur les pieds : que se passe-t-il si l’un s’apprête à modifier deux variables liées entre elles à la suite, commence à en modifier une, mais que le second thread lit les deux variables sans que la deuxième variable n’ait encore été modifiée, et qu’il obtient des résultats contradictoires en conséquence ? La programmation avec les threads est plein de bugs tordus comme ça.<br>
<br>
Pour les éviter, il faut « bloquer » explicitement des zones du code qui touchent une même variable pour éviter qu’elles ne soient exécutées par deux programmes à la fois, c’est compliqué et ça créé des sacrés sacs de nœuds.<br>
</p>
</li>
<li>
<p>Les threads représentent un léger coût en performance et en mémoire. Il faut que le système les réveillent, les endorment, les réveillent… avec toutes les variables et le contexte qui vont avec à chaque fois. C’est pour ça que les serveurs qui sont utilisés pour de fortes nécessités de performances, comme Nginx, évitent d’utiliser des threads.</p>
</li>
</ul>
<p>Maintenant, quelle est l’alternative aux threads ? Les <strong>boucles événementielles</strong>. Le principe est simple : le programme se met d’accord avec le noyau pour écouter sur plusieurs sockets (ou plusieurs sockets + une entrée de terminal + un périphérique spécial, etc.) à la fois, et se faire réveiller par le noyau uniquement quand il y a de nouvelles données / un nouvel évènement à traiter.</p>
<p>Ainsi, il n’a <strong>qu’un seul fil d’exécution</strong> et qu’un seul état (et n’utilise qu’un seul cœur, sauf si tu commences à mettre une boucle événementielle sur chaque thread…).</p>
<p>Le module <code>select</code> permet d’utiliser une des API bas-niveau qui sont exposées par le noyau pour permettre des boucles événementielles sur plusieurs descripteurs (sockets, fichiers…), l’API <code>select</code>, disponible sur pratiquement toutes les plateformes. L’idée est donc que tu lui passes plusieurs sockets et que ton programme se fasse réveiller au bon moment. D’autres API plus récentes s’appellent <code>poll</code>, <code>epoll</code> (sous Linux) ou <code>kqueue</code> (sous FreeBSD), mais elles sont d’abord utilisées en C et ne sont pas disponibles sous toutes les plateformes.</p>
<p><code>asyncio</code> est une surcouche par-dessus ces différentes API qui te permettra d’utiliser ce qu’on appelle des <strong>coroutines</strong> : des fonctions qui te permettront d’avoir un programme avec un seul fil d’exécution et un seul état, mais chaque fonction s’endormira individuellement et repassera la main à la boucle évènementielle quand tu auras un appel bloquant (lecture, écriture… sur par exemple un socket) à faire. Ces appels sont préfixés par le mot-clef <code>await</code> dans les versions récentes Python, et les définitions de coroutines sont préfixées par le mot-clef <code>async</code>.</p>
<p>Les coroutines sont une des différentes approches pour faire ce qu’on appelle de l’asynchrone (intégrer proprement une boucle événementielle à ton programme). Une autre approche est celle des callbacks, utilisée par Node.JS (une autre fonction, en général imbriquée dans la première, sera appelée « à retardement » quand la boucle évènementielle aura retourné quelque chose). Il y a aussi des bibliothèques qui t’encouragent à faire des callbacks en Python, mais c’est moins fréquent.</p>
<p>Dans tous les cas, le module <code>select</code> est peu utilisé car c’est principalement une « brique » qui te permet d’accéder à une API bas-niveau, pour des besoins bas-niveau.</p>
<p>Bonne journée,</p>[Python] Multiplexage avec le module select, message #2159422020-02-19T21:52:30+01:00entwanne/@entwannehttps://zestedesavoir.com/forums/sujet/13640/python-multiplexage-avec-le-module-select/?page=1#p215942<p>C’est juste une technique différente.
Ça permet d’avoir des appels qui ne bloquent pas le <em>thread</em> courant et ça peut être utile quand on ne veut justement aps instacier de nouveaux <em>threads</em> et avoir à les gérer.</p>
<p>Par ailleurs, note que le module <a href="https://docs.python.org/3/library/selectors.html"><code>selectors</code></a> fournit une interface plus haut-niveau de <em>multiplexing</em>.
La page de documentation comporte aussi des exemples.</p>[Python] Multiplexage avec le module select, message #2159382020-02-19T21:18:43+01:00buffalo974/@buffalo974https://zestedesavoir.com/forums/sujet/13640/python-multiplexage-avec-le-module-select/?page=1#p215938<p>salut, qu’apporte le multiplexing avec le module select par rapport aux threads ?
auriez vous des exemples faciles à comprendre ?</p>Des transactions avec yield ?, message #442992015-02-17T16:06:00+01:00Vayel/@Vayelhttps://zestedesavoir.com/forums/sujet/2468/des-transactions-avec-yield/?page=1#p44299<p>Non, ce que je veux dire c'est que la fonction <code>isAnd</code> doit se situer dans le module <code>Locator</code>. Celui <code>Data</code> ne fournit que des getters, des setters et des checkers.</p>
<p>Par rapport au projet dans sa globalité, tu as plus d'informations <a href="http://zestedesavoir.com/forums/sujet/2228/orchardtreatment/">ici</a>.</p>
<p>Dans le cas présent, je travaille sur le module de localisation. Le module <code>Data</code> contient la carte et fournit des méthodes pour la manipuler (les deux communiquent via RPC). Le module de localisation permet de mettre à jour la position du tracteur sur la carte. En fonction des informations qu'il reçoit de la carte électronique, il détermine la zone courante (en utilisant des informations sur les zones fournies par le module <code>Data</code> : leurs coordonnées GPS, leur distance au début du rang… tout dépend de comment l'agriculteur décide de se repérer) et demande au module <code>Data</code> de mettre à jour la position sur la carte.</p>
<p>Pour faire ça plus proprement, il y aurait peut-être la classe <a href="https://twistedmatrix.com/documents/14.0.1/core/howto/defer.html#deferredlist"><code>DeferredList</code></a> de twisted.</p>Des transactions avec yield ?, message #442212015-02-17T12:28:37+01:00anonyme/@anonymehttps://zestedesavoir.com/forums/sujet/2468/des-transactions-avec-yield/?page=1#p44221<blockquote>
<p>Le code dans la fonction appartient au module Locator, pas au module Data.</p>
</blockquote>
<p>Oui, c'est pour ça que j'ai bien marqué les entêtes Wamp. J'ai clipsé le contenu des deux fichiers dans un seul bloc de code. <img alt=":)" src="/static/smileys/smile.png"></p>
<p>Effectivement le code reste crade. Mais en même temps je ne vois pas vraiment comment tu peux faire autrement. Sans compter que tu n'as pas expliqué l'objectif final de ton projet ? A quoi ça va servir ?</p>Des transactions avec yield ?, message #442102015-02-17T11:57:49+01:00Vayel/@Vayelhttps://zestedesavoir.com/forums/sujet/2468/des-transactions-avec-yield/?page=1#p44210<p>Tout d'abord, merci pour l'investissement. <img alt="^^" src="/static/smileys/hihi.png"> Néanmoins, il y a quelques soucis :</p>
<ul>
<li>Le code dans la fonction est toujours aussi crade.</li>
<li>Le code dans la fonction appartient au module <code>Locator</code>, pas au module <code>Data</code>. En fait, le second offre une API au premier. Je fournis le module <code>Data</code> et le programmeur l'utilise pour écrire son propre module <code>Locator</code> (plus <a href="http://zestedesavoir.com/forums/sujet/2228/orchardtreatment/">ici</a>).</li>
<li>La valeur de retour est superflue : autant lever directement l'exception, avec le message défini dans le <code>if</code>. Mais si tu ne connais pas WAMP, il est normal que tu ne saches pas que l'exception (son message) est transmise à celui qui fait l'appel via RPC (donc, ici, le client Web).</li>
</ul>
<p>Thanks!</p>Des transactions avec yield ?, message #442032015-02-17T11:44:56+01:00anonyme/@anonymehttps://zestedesavoir.com/forums/sujet/2468/des-transactions-avec-yield/?page=1#p44203<p>Bonjour,</p>
<p>Je ne sais pas si ça peut te convenir, mais tu peux toujours écrire ça :</p>
<table class="codehilitetable"><tr><td class="linenos"><div class="linenodiv"><pre> 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</pre></div></td><td class="code"><div class="codehilite"><pre><span class="nd">@wamp.register</span><span class="p">(</span><span class="s">u'data.isAnd'</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">isAnd</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">markpos</span><span class="p">,</span> <span class="n">pos</span><span class="p">):</span>
<span class="k">try</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">markables</span><span class="p">[</span><span class="n">markpos</span><span class="p">]</span>
<span class="k">except</span> <span class="ne">IndexError</span><span class="p">:</span>
<span class="k">return</span> <span class="mi">0</span>
<span class="k">else</span><span class="p">:</span>
<span class="k">try</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">positions</span><span class="p">[</span><span class="n">pos</span><span class="p">]</span>
<span class="k">except</span> <span class="ne">IndexError</span><span class="p">:</span>
<span class="k">return</span> <span class="mi">1</span>
<span class="k">else</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">positions</span><span class="p">[</span><span class="n">markpos</span><span class="p">]</span> <span class="o">=</span> <span class="s">'marked'</span>
<span class="bp">self</span><span class="o">.</span><span class="n">position</span> <span class="o">=</span> <span class="n">pos</span>
<span class="k">print</span><span class="p">(</span><span class="s">'Positions: {}'</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">positions</span><span class="p">))</span>
<span class="k">print</span><span class="p">(</span><span class="s">'Positions: {}'</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">position</span><span class="p">))</span>
<span class="k">return</span> <span class="mi">2</span>
<span class="nd">@wamp.register</span><span class="p">(</span><span class="s">u'locator.move'</span><span class="p">)</span>
<span class="nd">@inlineCallbacks</span>
<span class="k">def</span> <span class="nf">move</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="k">print</span><span class="p">(</span><span class="s">'Move !'</span><span class="p">)</span>
<span class="n">pos</span> <span class="o">=</span> <span class="k">yield</span> <span class="bp">self</span><span class="o">.</span><span class="n">call</span><span class="p">(</span><span class="s">'data.get_position'</span><span class="p">)</span>
<span class="n">direction</span> <span class="o">=</span> <span class="k">yield</span> <span class="bp">self</span><span class="o">.</span><span class="n">call</span><span class="p">(</span><span class="s">'data.get_direction'</span><span class="p">)</span>
<span class="n">next_pos</span> <span class="o">=</span> <span class="n">pos</span> <span class="o">+</span> <span class="n">direction</span>
<span class="n">isAnd</span> <span class="o">=</span> <span class="k">yield</span> <span class="bp">self</span><span class="o">.</span><span class="n">call</span><span class="p">(</span><span class="s">'data.isAnd'</span><span class="p">,</span> <span class="n">pos</span><span class="p">,</span> <span class="n">next_pos</span><span class="p">)</span>
<span class="k">if</span> <span class="n">isAnd</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">publish</span><span class="p">(</span>
<span class="s">'error'</span><span class="p">,</span>
<span class="s">'The pos {} is not markable.'</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">pos</span><span class="p">)</span>
<span class="p">)</span>
<span class="k">elif</span> <span class="n">isAnd</span> <span class="o">==</span> <span class="mi">1</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">publish</span><span class="p">(</span>
<span class="s">'error'</span><span class="p">,</span>
<span class="s">'The pos {} does not exist.'</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">next_pos</span><span class="p">)</span>
<span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">call</span><span class="p">(</span><span class="s">'data.sth'</span><span class="p">)</span>
</pre></div>
</td></tr></table>
<p>Après je n'ai pas pu le tester, il faudrait que je télécharge les modules. <img alt=":)" src="/static/smileys/smile.png"></p>Des transactions avec yield ?, message #441972015-02-17T11:32:17+01:00Vayel/@Vayelhttps://zestedesavoir.com/forums/sujet/2468/des-transactions-avec-yield/?page=1#p44197<p>Bon, j'ai encore voulu utiliser une usine à gaz pour faire des cookies… Rassembler la vérification et l'affectation dans une même fonction complique les choses pour rien. Restons donc avec deux fonctions <code>check</code> et <code>set</code>. Par contre, vu comme la première version, avec les <code>if</code>, est sale, utilisons plutôt les exceptions (<a href="https://github.com/Vayel/WAMPLab/tree/master/transaction/v3">v3</a>) :</p>
<table class="codehilitetable"><tr><td class="linenos"><div class="linenodiv"><pre> 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</pre></div></td><td class="code"><div class="codehilite"><pre><span class="kn">from</span> <span class="nn">twisted.internet.defer</span> <span class="kn">import</span> <span class="n">inlineCallbacks</span>
<span class="kn">from</span> <span class="nn">autobahn</span> <span class="kn">import</span> <span class="n">wamp</span>
<span class="kn">from</span> <span class="nn">autobahn.twisted.wamp</span> <span class="kn">import</span> <span class="n">ApplicationSession</span>
<span class="kn">from</span> <span class="nn">autobahn.wamp.exception</span> <span class="kn">import</span> <span class="n">ApplicationError</span>
<span class="kn">from</span> <span class="nn">autobahn.twisted.wamp</span> <span class="kn">import</span> <span class="n">ApplicationRunner</span>
<span class="k">class</span> <span class="nc">Locator</span><span class="p">(</span><span class="n">ApplicationSession</span><span class="p">):</span>
<span class="nd">@inlineCallbacks</span>
<span class="k">def</span> <span class="nf">onJoin</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">details</span><span class="p">):</span>
<span class="k">yield</span> <span class="bp">self</span><span class="o">.</span><span class="n">register</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span>
<span class="nd">@wamp.register</span><span class="p">(</span><span class="s">u'locator.move'</span><span class="p">)</span>
<span class="nd">@inlineCallbacks</span>
<span class="k">def</span> <span class="nf">move</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="sd">"""Try to mark the current position and to go to the next one. Fail if </span>
<span class="sd"> the current position is not markable or if the next position does not </span>
<span class="sd"> exist.</span>
<span class="sd"> """</span>
<span class="k">print</span><span class="p">(</span><span class="s">'Move!'</span><span class="p">)</span>
<span class="n">pos</span> <span class="o">=</span> <span class="k">yield</span> <span class="bp">self</span><span class="o">.</span><span class="n">call</span><span class="p">(</span><span class="s">'data.get_position'</span><span class="p">)</span>
<span class="n">direction</span> <span class="o">=</span> <span class="k">yield</span> <span class="bp">self</span><span class="o">.</span><span class="n">call</span><span class="p">(</span><span class="s">'data.get_direction'</span><span class="p">)</span>
<span class="n">next_pos</span> <span class="o">=</span> <span class="n">pos</span> <span class="o">+</span> <span class="n">direction</span>
<span class="k">try</span><span class="p">:</span>
<span class="k">yield</span> <span class="bp">self</span><span class="o">.</span><span class="n">call</span><span class="p">(</span><span class="s">'data.check_markable'</span><span class="p">,</span> <span class="n">pos</span><span class="p">)</span>
<span class="k">yield</span> <span class="bp">self</span><span class="o">.</span><span class="n">call</span><span class="p">(</span><span class="s">'data.check_position'</span><span class="p">,</span> <span class="n">next_pos</span><span class="p">)</span>
<span class="k">except</span> <span class="n">ApplicationError</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
<span class="k">raise</span> <span class="n">e</span>
<span class="k">else</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">call</span><span class="p">(</span><span class="s">'data.mark_position'</span><span class="p">,</span> <span class="n">pos</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">call</span><span class="p">(</span><span class="s">'data.set_position'</span><span class="p">,</span> <span class="n">next_pos</span><span class="p">)</span>
<span class="k">finally</span><span class="p">:</span>
<span class="k">try</span><span class="p">:</span>
<span class="k">yield</span> <span class="bp">self</span><span class="o">.</span><span class="n">call</span><span class="p">(</span><span class="s">'data.check_sth'</span><span class="p">)</span>
<span class="k">except</span> <span class="n">ApplicationError</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
<span class="k">raise</span> <span class="n">e</span>
<span class="k">else</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">call</span><span class="p">(</span><span class="s">'data.do_sth'</span><span class="p">)</span>
<span class="k">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="s">"__main__"</span><span class="p">:</span>
<span class="k">print</span><span class="p">(</span><span class="s">'Starting Locator component...'</span><span class="p">)</span>
<span class="n">ApplicationRunner</span><span class="p">(</span><span class="n">url</span><span class="o">=</span><span class="s">'ws://localhost:8080/ws'</span><span class="p">,</span> <span class="n">realm</span><span class="o">=</span><span class="s">'realm1'</span><span class="p">)</span><span class="o">.</span><span class="n">run</span><span class="p">(</span><span class="n">Locator</span><span class="p">)</span>
</pre></div>
</td></tr></table>
<p>A présent, il faut chercher à offrir une interface propre à la place de ce code spaghetti.</p>Des transactions avec yield ?, message #441022015-02-16T19:21:17+01:00Vayel/@Vayelhttps://zestedesavoir.com/forums/sujet/2468/des-transactions-avec-yield/?page=1#p44102<p>Bonjour !</p>
<p>Pour le contexte, je travaille avec <a href="http://wamp.ws/">WAMP</a>, <a href="http://crossbar.io/">Crossbar.io</a> et <a href="http://autobahn.ws/python/">AutobahnPython</a>. Ce n'est pas très important, mis à part que ça implique que tout ce qui suit est majoritairement asynchrone (basé sur <a href="https://twistedmatrix.com/trac/">twisted</a>, notamment avec le décorateur <a href="http://hackedbellini.org/development/writing-asynchronous-python-code-with-twisted-using-inlinecallbacks/">inlineCallbacks</a>). Et je souhaiterais faire <a href="https://github.com/Vayel/WAMPLab/tree/master/transaction">ça</a>. J'en déduis alors le code suivant :</p>
<p><a href="https://github.com/Vayel/WAMPLab/blob/master/transaction/v1/data.py">data.py</a> et <a href="https://github.com/Vayel/WAMPLab/blob/master/transaction/v1/locator.py">locator.py</a></p>
<p>Seulement, c'est pas optimal : j'ai deux fonctions (<code>is_</code> et <code>set_</code>) pour chaque attribut de ma classe <code>Data</code> et des <code>if</code> de partout dans mon <code>Locator</code>. Et encore, je n'ai pas beaucoup de conditions ici.</p>
<p>Du coup, je voudrais fusionner les <code>is_</code> et les <code>set_</code>. Sauf qu'avec mon histoire de transaction, il faut que je teste si tous les arguments de chaque fonction sont corrects avant d'exécuter ces dernières (faire tous les <code>is_</code> <strong>puis</strong> tous les <code>set_</code>). Du coup, je me suis dis que j'allais passer par un <a href="http://sametmax.com/comment-utiliser-yield-et-les-generateurs-en-python/">générateur</a>, pour modéliser cette coupure entre vérification et affectation :</p>
<p><a href="https://github.com/Vayel/WAMPLab/blob/master/transaction/v2/data.py">data.py v2</a> et <a href="https://github.com/Vayel/WAMPLab/blob/master/transaction/v2/locator.py">locator.py v2</a> avec <a href="https://github.com/Vayel/WAMPLab/blob/master/transaction/v2/tools.py">tools.py</a></p>
<p>Sauf que pickle ne veut pas me sérialiser mon générateur. J'en viens à me demander s'il s'agit de la bonne manière de faire.</p>
<p>Merci !</p>