{"id":1529,"date":"2015-09-18T09:37:43","date_gmt":"2015-09-18T13:37:43","guid":{"rendered":"http:\/\/bioinfo.iric.ca\/fr\/?p=1529"},"modified":"2017-04-29T17:11:30","modified_gmt":"2017-04-29T21:11:30","slug":"python-iterateur-vs-generateur","status":"publish","type":"post","link":"https:\/\/bioinfo.iric.ca\/fr\/python-iterateur-vs-generateur\/","title":{"rendered":"[python] it\u00e9rateur vs g\u00e9n\u00e9rateur"},"content":{"rendered":"<p>En python, nous retrouvons les concepts d&rsquo;it\u00e9rateurs et de g\u00e9n\u00e9rateurs. Vous utilisez s\u00fbrement d\u00e9j\u00e0 les it\u00e9rateurs couramment sans m\u00eame savoir comment les nommer. C&rsquo;est important de savoir que ces deux concepts existent, car ils ont des r\u00e9percussions diff\u00e9rentes au niveau de la m\u00e9moire. Pour les petits programmes qui traitent de petits jeux de donn\u00e9es, pas de probl\u00e8me. Mais pour les gros jeux de donn\u00e9es, c&rsquo;est autre chose. Que sont-ils au juste?<\/p>\n<h3><strong>Les it\u00e9rateurs<\/strong><\/h3>\n<p>Quand vous\u00a0parcourez les \u00e9l\u00e9ments d&rsquo;une liste un par un, on appelle cela l\u2019it\u00e9ration:<\/p>\n<pre><code class=\"python\"> \r\n&gt;&gt;&gt; lst = [1,2,3]\r\n&gt;&gt;&gt; for i in lst:\r\n...  print(i*i)\r\n<\/code>\r\n1\r\n4\r\n9\r\n<\/pre>\n<p>Et quand on utilise une liste en intention (<em>list comprehension<\/em>), on cr\u00e9\u00e9 une liste, donc un objet it\u00e9rable.<\/p>\n<pre><code class=\"python\"> \r\n&gt;&gt;&gt; lst = [x*x for x in [1,2,3]]  # [1, 4, 9]\r\n&gt;&gt;&gt; print(lst)\r\n<\/code>\r\n[1, 4, 9]\r\n<code class=\"python\"> \r\n&gt;&gt;&gt; for i in lst:\r\n...  print(i)\r\n<\/code>\r\n1\r\n4\r\n9\r\n<\/pre>\n<h3><strong>Les g\u00e9n\u00e9rateurs<\/strong><\/h3>\n<p>En rempla\u00e7ant les [] \u00a0par des \u00a0(), on cr\u00e9e des expressions g\u00e9n\u00e9ratrices (on ne cr\u00e9e plus de liste).<br \/>\nAvec les g\u00e9n\u00e9rateurs, les donn\u00e9es ne sont pas sauvegard\u00e9es en m\u00e9moire dans la variable <code>lst<\/code>, mais vont \u00eatre g\u00e9n\u00e9r\u00e9es \u00e0 la vol\u00e9e (\u00e0 la demande ou au fur et \u00e0 mesure).<br \/>\n<span style=\"text-decoration: underline;\"><strong>Attention:<\/strong><\/span> La g\u00e9n\u00e9ration des donn\u00e9es \u00e0 la vol\u00e9e ne permet pas de les relire une seconde fois et si vous essayez tout de m\u00eame, aucune erreur ne sera produite pour vous pr\u00e9venir.<\/p>\n<pre><code class=\"python\"> \r\n&gt;&gt;&gt; lst = (x*x for x in [1,2,3])  # [1, 4, 9]\r\n&gt;&gt;&gt; print(lst)\r\n<\/code>\r\n&lt;generator object &lt;genexpr&gt; at 0x1933640&gt;\r\n<\/pre>\n<p>Ici \u00ab\u00a0genexpr\u00a0\u00bb signifie <em>generator expression<\/em> (et non <em>gene expression<\/em> pour les biologistes).<\/p>\n<pre><code class=\"python\"> \r\n&gt;&gt;&gt; for i in lst:\r\n...  print(i)\r\n<\/code>\r\n1\r\n4\r\n9\r\n<code class=\"python\"> \r\n&gt;&gt;&gt; for i in lst:\r\n...  print(i)\r\n<\/code>\r\n<code>\r\n# Rien ne s'est affich\u00e9\r\n<\/code>\r\n<\/pre>\n<p>Vous remarquerez qu&rsquo;on d\u00e9sire imprimer la liste lst deux fois, mais que les r\u00e9sultats ne s&rsquo;affiche qu&rsquo;une seule fois.<\/p>\n<p><span style=\"text-decoration: underline;\"><strong>Astuce:<\/strong><\/span> Quand on commence \u00e0 appr\u00e9cier l&rsquo;utilisation des g\u00e9n\u00e9rateurs, il est particuli\u00e8rement int\u00e9ressant de les imbriquer (performance, lisibilit\u00e9 du code). Mais attention, la lecture de la deuxi\u00e8me liste lst2 effacera la premi\u00e8re!<\/p>\n<pre><code class=\"python\"> \r\n&gt;&gt;&gt; lst1\u00a0= (x*x for x in [1,2,3])   # [1, 4, 9]\r\n&gt;&gt;&gt; lst2 = (x+x for x in lst1)  # [2, 8, 18]\r\n&gt;&gt;&gt; for i in lst2:\r\n...  print(i)\r\n<\/code>\r\n2\r\n8\r\n18\r\n<code class=\"python\"> \r\n&gt;&gt;&gt; for i in lst1:\r\n...  print(i)\r\n<\/code>\r\n<code>\r\n# Rien ne s'est affich\u00e9\r\n<\/code>\r\n<\/pre>\n<h2><strong>Avantages\/inconv\u00e9nients des g\u00e9n\u00e9rateurs<\/strong><\/h2>\n<p><span style=\"text-decoration: underline;\"><strong>Si<\/strong> vous avez besoin d&rsquo;acc\u00e9der une seule fois \u00e0 vos donn\u00e9es,<\/span> vous allez gagner de l&rsquo;espace m\u00e9moire (les donn\u00e9es sont g\u00e9n\u00e9r\u00e9es \u00e0 la demande) et votre programme sera plus rapide.<\/p>\n<p><span style=\"text-decoration: underline;\"><strong>Maintenant<\/strong><\/span>, si vous devez acc\u00e9der plusieurs fois \u00e0 vos donn\u00e9es, vous allez toujours gagner en espace m\u00e9moire, mais votre programme sera plus lent (les donn\u00e9es devront \u00eatre reg\u00e9n\u00e9r\u00e9es \u00e0\u00a0chaque demande et il faut recr\u00e9er les g\u00e9n\u00e9rateurs avant chaque demande). Il est g\u00e9n\u00e9ralement d\u00e9conseill\u00e9 d&rsquo;utiliser les g\u00e9n\u00e9rateurs dans ce derniers cas.<\/p>\n<p>Pour finir, voici un petit exemple pour vous donner\u00a0une id\u00e9e de\u00a0la performance des g\u00e9n\u00e9rateurs quand ils sont correctement utilis\u00e9s.<\/p>\n<pre><code class=\"python\"> \r\nimport os\r\nimport gc\r\nimport psutil\r\n\r\nnum = 10000000\r\nrep = 500\r\n\r\ndef mem_usage_in_MB(proc):\r\n  return  proc.memory_info()[0] \/ float(2 ** 20)\r\n\r\nproc = psutil.Process(os.getpid())\r\nmem0 = mem_usage_in_MB(proc)\r\ntoto = (x*x for x in range(num))\r\ntata = (x+x for x in toto)\r\ntutu = (x-1 for x in tata)\r\nprint(\"mem generator: \" + str(mem_usage_in_MB(proc) - mem0) + \"MB\")\r\nmem0 = mem_usage_in_MB(proc)\r\ntoto = [x*x for x in range(num)]\r\ntoto = [x+x for x in toto]\r\ntoto = [x-1 for x in toto]\r\nprint(\"mem iterator: \" + str(mem_usage_in_MB(proc) - mem0) + \"MB\")\r\n\r\n\r\nimport timeit\r\ndef test(t, num):\r\n  toto = (x*x for x in range(num)) if t == \"gen\" else [x*x for x in range(num)]\r\n  sum(toto)\r\n\r\ndef test2(t, num):\r\n  toto = (x*x for x in range(num)) if t == \"gen\" else [x*x for x in range(num)]\r\n  toto = (x+x for x in toto) if t == \"gen\" else [x+x for x in toto]\r\n  toto = (x-1 for x in toto) if t == \"gen\" else [x-1 for x in toto]\r\n  sum(toto)\r\n\r\nprint(\"test time generator:\" + str(timeit.timeit(\"test(\\\"gen\\\",\" + str(num) + \")\", setup=\"from __main__ import test\", number=rep)))\r\nprint(\"test time iterator:\" + str(timeit.timeit(\"test(\\\"iter\\\",\" + str(num) + \")\", setup=\"from __main__ import test\", number=rep)))\r\nprint(\"test2 time generator:\" + str(timeit.timeit(\"test(\\\"gen\\\",\" + str(num) + \")\", setup=\"from __main__ import test\", number=rep)))\r\nprint(\"test2 time iterator:\" + str(timeit.timeit(\"test(\\\"iter\\\",\" + str(num) + \")\", setup=\"from __main__ import test\", number=rep)))\r\n# avec python3\r\n<\/code>\r\nmem generator: 0.00390625MB\r\nmem iterator: 387.8984375MB\r\ntest time generator:730.7246094942093\r\ntest time iterator:765.0462868176401\r\ntest2 time generator:727.7452643960714\r\ntest2 time iterator:768.4699434302747\r\n<code class=\"python\">\r\n# avec python2\r\n<\/code>\r\nmem generator: 310.72265625MB\r\nmem iterator: 545.578125MB\r\ntest time generator:801.186733007\r\ntest time iterator:757.989295006\r\ntest2 time generator:810.537645102\r\ntest2 time iterator:939.240092993\r\n<\/pre>\n<p>&nbsp;<\/p>\n<p><span style=\"text-decoration: underline;\"><strong>Note:<\/strong><\/span> Ceci n&rsquo;est qu&rsquo;une introduction sur les g\u00e9n\u00e9rateurs, vus par le biais des listes en intention (tr\u00e8s utilis\u00e9es par les programmeurs python). Pour en savoir plus, je vous invite \u00e0 regarder cette <a href=\"http:\/\/www.dabeaz.com\/generators\/Generators.pdf\">pr\u00e9sentation<\/a> et \u00e0 vous documenter sur le mot cl\u00e9 <a href=\"https:\/\/www.google.ca\/webhp?sourceid=chrome-instant&amp;ion=1&amp;espv=2&amp;ie=UTF-8#q=python%20yield\">yield<\/a>.<br \/>\n<span style=\"text-decoration: underline;\"><strong>Note 2:<\/strong><\/span> Avec Python2 il faut remplacez \u00ab\u00a0range\u00a0\u00bb par \u00ab\u00a0xrange\u00a0\u00bb pour obtenir une meilleure performance, mais le code ne sera plus compatible Python3.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>En python, nous retrouvons les concepts d&rsquo;it\u00e9rateurs et de g\u00e9n\u00e9rateurs. Vous utilisez s\u00fbrement d\u00e9j\u00e0 les it\u00e9rateurs couramment sans m\u00eame savoir comment les nommer. C&rsquo;est important de savoir que ces deux concepts existent, car ils ont des r\u00e9percussions diff\u00e9rentes au niveau de la m\u00e9moire. Pour les petits programmes qui traitent de petits jeux de donn\u00e9es, pas de probl\u00e8me. Mais pour les gros jeux de donn\u00e9es, c&rsquo;est autre chose. Que sont-ils au juste? Les it\u00e9rateurs Quand vous\u00a0parcourez les \u00e9l\u00e9ments d&rsquo;une liste un <a href=\"https:\/\/bioinfo.iric.ca\/fr\/python-iterateur-vs-generateur\/\"> [&#8230;]<\/a><\/p>\n","protected":false},"author":9,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2}},"categories":[32,26],"tags":[],"class_list":["post-1529","post","type-post","status-publish","format-standard","hentry","category-performance-fr-2","category-langage-python"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/bioinfo.iric.ca\/fr\/wp-json\/wp\/v2\/posts\/1529","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/bioinfo.iric.ca\/fr\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/bioinfo.iric.ca\/fr\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/bioinfo.iric.ca\/fr\/wp-json\/wp\/v2\/users\/9"}],"replies":[{"embeddable":true,"href":"https:\/\/bioinfo.iric.ca\/fr\/wp-json\/wp\/v2\/comments?post=1529"}],"version-history":[{"count":27,"href":"https:\/\/bioinfo.iric.ca\/fr\/wp-json\/wp\/v2\/posts\/1529\/revisions"}],"predecessor-version":[{"id":1569,"href":"https:\/\/bioinfo.iric.ca\/fr\/wp-json\/wp\/v2\/posts\/1529\/revisions\/1569"}],"wp:attachment":[{"href":"https:\/\/bioinfo.iric.ca\/fr\/wp-json\/wp\/v2\/media?parent=1529"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/bioinfo.iric.ca\/fr\/wp-json\/wp\/v2\/categories?post=1529"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/bioinfo.iric.ca\/fr\/wp-json\/wp\/v2\/tags?post=1529"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}