{"id":1460,"date":"2015-08-19T20:37:33","date_gmt":"2015-08-19T19:37:33","guid":{"rendered":"https:\/\/www.entropywins.wtf\/blog\/?p=1460"},"modified":"2018-08-19T03:20:40","modified_gmt":"2018-08-19T02:20:40","slug":"lazy-iterators-in-php-and-python","status":"publish","type":"post","link":"https:\/\/www.entropywins.wtf\/blog\/2015\/08\/19\/lazy-iterators-in-php-and-python\/","title":{"rendered":"Lazy iterators in PHP and Python"},"content":{"rendered":"<p>I recently watched <a href=\"http:\/\/cleancoders.com\/episode\/clean-code-episode-34\/show\">Clean Code Episode 34: Pattern Apocalypse<\/a>, which is about several <a href=\"https:\/\/en.wikipedia.org\/wiki\/Software_design_pattern\">design patterns<\/a>, including the <a href=\"https:\/\/en.wikipedia.org\/wiki\/Iterator_pattern\">Iterator<\/a>. Afterwards I took some example code from this episode and tried writing it first in PHP and then in Python. While there is no rocket science involved in any of it, I did hit a few bumps and learned a thing or two. In this blog post I&#8217;m following the Share What You Learn pattern from <a href=\"https:\/\/www.goodreads.com\/book\/show\/5608045-apprenticeship-patterns\">Apprenticeship Patterns<\/a> by sharing my experiences.<\/p>\n<p><strong>Printing the squares of integers<\/strong><\/p>\n<p>One way of writing an application that prints the squares\u00a0 of the first n integers (in Java) is as follows:<\/p>\n<pre class=\"lang:java decode:true\">for (int i=1; i&lt;=25; i++) {\n    System.out.printLn(i*i);\n}<\/pre>\n<p>In this Clean Code episode, Unclebob explains that he finds this code &#8220;quite awefull&#8221;, even though it is simple, because the calculation is buried within the loop, driven by it and coupled to it. And while not explicitly stated in the episode, there is also the binding of the algorithm to the output call. This coupling can be avoided using iterators, as follows:<\/p>\n<pre class=\"lang:java decode:true \">PrintAll(take(25, SquaresOf(Integers.all())))<\/pre>\n<p>PrintAll takes a collection, and speaks for itself when it comes to its function. &#8220;take&#8221; returns a collection with the first n elements from the collection it got. SquaresOf returns a collection of integers which are the squares of those in the collection it got. &#8220;Integers.all&#8221; returns a collection of all positive integers. Of course, this last collection is an Iterator and not some kind of infinite list. SquaresOf is also an Iterator, which lazily applies the square function on an element at the time of request.<\/p>\n<p>One thing that stood out to me was how much scaffolding code Unclebob had written to create the constructs used here. (These are not listed in this blog post, if you&#8217;re curious, go watch the episode itself.) As I&#8217;m not a Java programmer, it&#8217;s unclear to me how much of that was needed, and how much was written for the sake of explaining the relevant Iterator concepts in a manner easily consumable by non-Java programmers. This made me wonder how much of that I&#8217;d need in PHP, which then led me to writing the code in PHP.<\/p>\n<p><strong>Lazy Iterators in PHP<\/strong><\/p>\n<p>Even though PHP is the primary language I use at work, and even though I think the Iterator pattern is quite cool and useful, sadly enough I do not get to use it often. This is due to a combination of PHPs horrid collection support, the limitations of type inference in PHP (or the lack when it comes to iterators) and me being constrained to using an outdated version of the language most of the time. That makes it all the more fun to play with Iterators, as for instance I did with what I wrote about in my &#8220;<a href=\"https:\/\/www.entropywins.wtf\/blog\/2014\/07\/14\/some-fun-with-iterators\/\">Some fun with iterators<\/a>&#8221; post.<\/p>\n<p>I started with replicating the example code from the outside, so starting with the &#8220;print all&#8221; part. I wanted to know if there is a sane way of doing that without using a loop.<\/p>\n<pre class=\"lang:php decode:true \">printAll( new ArrayIterator( [ 1, 2, 3 ] ) );\n\nfunction printAll( $elements ) {\n    array_walk( $elements, 'print' );\n}<\/pre>\n<p>Unfortunately you cannot do that, so I had to create a new function. My first inclination was to create a named &#8220;printLine&#8221; function, which could then also be used elsewhere. That&#8217;d however force me to refer to this function using a string, which is another one of my PHP pet peeves, since it breaks static code analysis. So I settled for the inline notation, which unfortunately is also more verbose than either the Java or Python one.<\/p>\n<pre class=\"lang:php decode:true\">function( $line ) { echo \"$line\\n\"; }<\/pre>\n<p>As a next step, I went for implementing the &#8220;take&#8221; function.<\/p>\n<pre class=\"lang:default decode:true \">printAll( take( 4, new ArrayIterator( [ 1, 2, 3, 4, 5 ] ) ) );<\/pre>\n<p>Unclebob implemented it using a for loop with a counter. I figured such a loop can be avoided in PHP by using the <a href=\"http:\/\/php.net\/manual\/en\/class.limititerator.php\">LimitIterator<\/a> provided by PHPs SPL.<\/p>\n<p>As soon as I did that, the output of my script disappeared. The cause of this resides in the printAll function, which uses array_walk on an Iterator. I knew I&#8217;d need to change that when I wrote it, as PHPs arrays and Iterators don&#8217;t work well together, though then it worked without me making the change and I forgot all about it. Turns out that array_walk works fine with an ArrayIterator, though not with an ArrayIterator wrapped in a LimitIterator. I decided to write a collection_walk that would work with both arrays and iterators:<\/p>\n<pre class=\"lang:default decode:true \">\/**\n * @param array|Iterator $collection\n * @param callable $function\n *\/\nfunction collection_walk( $collection, callable $function ) {\n    array_walk( collection_to_array( $collection ), $function );\n}\n\n\/**\n * @param array|Iterator $collection\n * @return array\n *\/\nfunction collection_to_array( $collection ) {\n    return is_array( $collection ) ? $collection : iterator_to_array( $collection );\n}<\/pre>\n<p>With that out of the way and writing an additional collection_to_iterator helper, the following worked fine for creating the take function:<\/p>\n<pre class=\"lang:php decode:true \">\/**\n * @param int $count\n * @param array|Iterator $collection\n * @return Iterator\n *\/\nfunction take( $count, $collection ) {\n    return new LimitIterator( collection_to_iterator( $collection ), 0, $count );\n}<\/pre>\n<p>I did waste a few seconds on incorrectly assuming that LimitIterator would take the limit after the collection, rather than also having an offset in there.<\/p>\n<p>As a next step I decided to go with the &#8220;all integers&#8221; part, as otherwise I&#8217;d have to write the &#8220;squares of iterator&#8221; without being forced to make it lazy.<\/p>\n<pre class=\"lang:php decode:true \">printAll( take( 5, Integers::all() ) );<\/pre>\n<p>As of PHP 5.4, this is really easy to implement using <a href=\"http:\/\/php.net\/manual\/en\/language.generators.overview.php\">generators<\/a>:<\/p>\n<pre class=\"lang:php decode:true \">class Integers {\n    public static function all() {\n        $i = 0;\n        while ( true ) {\n            yield ++$i;\n        }\n    }\n}<\/pre>\n<p>The final step was of course adding in the squaresOf function:<\/p>\n<pre class=\"lang:php decode:true \">printAll( take( 5, squaresOf( Integers::all() ) ) );<\/pre>\n<p>All this iterator needs to do is perform a lazy map. As far as I can tell, PHP does not provide any lazy map functions, so I created my own. Again, generators make this rather easy:<\/p>\n<pre class=\"lang:php decode:true\">\/**\n * @param array|Iterator $collection\n * @return Iterator\n *\/\nfunction squaresOf( $collection ) {\n    return collection_map( $collection, function( $number ) { return $number ** 2; } );\n}\n\n\/**\n * @param array|Iterator $collection\n * @param callable $function\n * @return Iterator\n *\/\nfunction collection_map( $collection, callable $function ) {\n    foreach( $collection as $element ) {\n        yield $function( $element );\n    }\n}<\/pre>\n<p>View the <a href=\"https:\/\/github.com\/JeroenDeDauw\/PrintSquares\/blob\/master\/printSquares.php\">full PHP code on GitHub<\/a>.<\/p>\n<p><strong>Lazy Iterators in Python<\/strong><\/p>\n<p>While I know Python basics, its not a language I regularly work in. I also implemented this algorithm in Python to generally freshen up my Python skills and perhaps learn some new language features I was not yet aware of. Furthermore after having to deal with PHPs nice collection handling, I was curious just how much smoother this would go in Python.<\/p>\n<p>I took a similar approach and started with the &#8220;print all&#8221; function:<\/p>\n<pre class=\"lang:python decode:true\">def print_all(collection):\n    [print(element) for element in collection]\n\n\nprint_all([1, 2, 3, 4])<\/pre>\n<p>Before ending up with that approach, I looked for something equivalent to PHPs array_walk. I tried using the map function by doing <span class=\"lang:python decode:true crayon-inline\">map(print, collection)<\/span> , though that does not work.<\/p>\n<p>To implement the take function I created<\/p>\n<pre class=\"lang:python decode:true\">def take(count, collection):\n    return collection[0:count]<\/pre>\n<p>Which is rather silly to do in Python, though I decided to stick to making it work with the same call code as in the example, and then to look at how to make that part of the code more idiomatic to Python later on. Also, this makes the take function non-lazy, so would need change later on anyway.<\/p>\n<p>The lazy iterator of all positive integers was as easy to implement as in PHP:<\/p>\n<pre class=\"lang:python decode:true\">class Integers:\n    @staticmethod\n    def all():\n        i = 0\n        while True:\n            i += 1\n            yield i<\/pre>\n<p>That brought me to<\/p>\n<pre class=\"lang:python decode:true\">print_all(take(3, Integers.all()))<\/pre>\n<p>Which went boom with the following error:<\/p>\n<blockquote><p>TypeError: &#8216;generator&#8217; object is not subscriptable<\/p><\/blockquote>\n<p>I changed the take function as follows:<\/p>\n<pre class=\"lang:python decode:true \">def take(count, collection):\n    return collection.takewhile(lambda x: x &lt; count)<\/pre>\n<p>Which resulted in some kind of progress: another error message:<\/p>\n<blockquote><p>AttributeError: &#8216;generator&#8217; object has no attribute &#8216;takewhile&#8217;<\/p><\/blockquote>\n<p>That puzzled me, as I figured takewhile is a method iterators have, and generators are iterators. I tried wrapping the thing in the iter function, which had no result on the error message. While searching for a solution, I found out that there is such a thing as iterator expressions, which are very similar to list comprehensions, in this <a href=\"http:\/\/anandology.com\/python-practice-book\/iterators.html\">excellent post on iterators and generators<\/a>. Using one of those I rewrote the take function in a working and lazy fashion:<\/p>\n<pre class=\"lang:python decode:true \">def take(count, collection):\n    return (x for x in collection if x &lt;= count)<\/pre>\n<p>While writing that code I did wonder if that would actually work as intended, or if it&#8217;d continue iterating over the generator forever. As I got the output I expected, I assumed it worked correct, until a minute later or so when I realized my IDE was was still running the script \ud83d\ude42<\/p>\n<p>After some more looking through the docs I realized that the takewhile function that I had tried to use earlier is not a method on iterators at all, but a function that takes an iterator. The facepalm was real. The reason I figured it was a method is because of things such as join being as method on string. Anyway, finally I got a working version of the take function:<\/p>\n<pre class=\"lang:python decode:true \">def take(count, collection):\n    return takewhile(lambda x: x &lt;= count, collection)<\/pre>\n<p>For the &#8220;squares of&#8221; function I was happy to have found a use case for the newly learned iterator expressions:<\/p>\n<pre class=\"lang:python decode:true \">def squares_of(collection):\n    return (x*x for x in collection)<\/pre>\n<pre class=\"lang:python decode:true \">print_all(take(5, squares_of(Integers.all())))<\/pre>\n<p>Of course at that point I realized that the take function was in fact still wrong, as it compared the squared number the the number count limit rather than an actual number count. So I added a counter to be used in the function passed to takewhile:<\/p>\n<pre class=\"lang:python decode:true \">def take(count, collection):\n    i = 0\n\n    def should_take(x):\n        i += 1\n        return i &lt;= count\n\n    return takewhile(should_take, collection)<\/pre>\n<p>I was surprised to find that &#8220;i&#8221; was undefined in should_take, as I figured it&#8217;d just be accessible from the parent function scope a-la-JavaScript. Which made me discover the &#8220;nonlocal&#8221; keyword.<\/p>\n<pre class=\"lang:python decode:true \">    def should_take(x):\n        nonlocal i\n        i += 1\n        return i &lt;= count<\/pre>\n<p>With that the algorithm works. The one part I&#8217;m still unhappy about it the implementation of the take function. Surely this can be done nicer. The inner should_take function has an unused parameter and using takewhile in this manner seems like a hack.<\/p>\n<p>View the <a href=\"https:\/\/github.com\/JeroenDeDauw\/PrintSquares\/blob\/master\/printSquares.py\">full Python code on GitHub<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>I recently watched Clean Code Episode 34: Pattern Apocalypse, which is about several design patterns, including the Iterator. Afterwards I&hellip;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":false,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2}},"categories":[7],"tags":[328,373,374,375,354,372,315,195,206],"class_list":["post-1460","post","type-post","status-publish","format-standard","hentry","category-programming","tag-clean-code","tag-design-patterns","tag-generators","tag-higher-order-functions","tag-iterator","tag-lazy-evaluation","tag-lessons-learned","tag-php","tag-python"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.4 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Lazy iterators in PHP and Python - Blog of Jeroen De Dauw<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.entropywins.wtf\/blog\/2015\/08\/19\/lazy-iterators-in-php-and-python\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Lazy iterators in PHP and Python - Blog of Jeroen De Dauw\" \/>\n<meta property=\"og:description\" content=\"I recently watched Clean Code Episode 34: Pattern Apocalypse, which is about several design patterns, including the Iterator. Afterwards I&hellip;\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.entropywins.wtf\/blog\/2015\/08\/19\/lazy-iterators-in-php-and-python\/\" \/>\n<meta property=\"og:site_name\" content=\"Blog of Jeroen De Dauw\" \/>\n<meta property=\"article:published_time\" content=\"2015-08-19T19:37:33+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2018-08-19T02:20:40+00:00\" \/>\n<meta name=\"author\" content=\"Jeroen\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@https:\/\/twitter.com\/JeroenDeDauw\" \/>\n<meta name=\"twitter:site\" content=\"@JeroenDeDauw\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Jeroen\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"9 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/www.entropywins.wtf\\\/blog\\\/2015\\\/08\\\/19\\\/lazy-iterators-in-php-and-python\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.entropywins.wtf\\\/blog\\\/2015\\\/08\\\/19\\\/lazy-iterators-in-php-and-python\\\/\"},\"author\":{\"name\":\"Jeroen\",\"@id\":\"https:\\\/\\\/www.entropywins.wtf\\\/blog\\\/#\\\/schema\\\/person\\\/4e2ef14f2ca7dc3a0ac137d1692b66b7\"},\"headline\":\"Lazy iterators in PHP and Python\",\"datePublished\":\"2015-08-19T19:37:33+00:00\",\"dateModified\":\"2018-08-19T02:20:40+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/www.entropywins.wtf\\\/blog\\\/2015\\\/08\\\/19\\\/lazy-iterators-in-php-and-python\\\/\"},\"wordCount\":1452,\"commentCount\":6,\"publisher\":{\"@id\":\"https:\\\/\\\/www.entropywins.wtf\\\/blog\\\/#\\\/schema\\\/person\\\/4e2ef14f2ca7dc3a0ac137d1692b66b7\"},\"keywords\":[\"Clean Code\",\"Design patterns\",\"Generators\",\"Higher order functions\",\"Iterator\",\"Lazy evaluation\",\"Lessons learned\",\"PHP\",\"Python\"],\"articleSection\":[\"Programming\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/www.entropywins.wtf\\\/blog\\\/2015\\\/08\\\/19\\\/lazy-iterators-in-php-and-python\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.entropywins.wtf\\\/blog\\\/2015\\\/08\\\/19\\\/lazy-iterators-in-php-and-python\\\/\",\"url\":\"https:\\\/\\\/www.entropywins.wtf\\\/blog\\\/2015\\\/08\\\/19\\\/lazy-iterators-in-php-and-python\\\/\",\"name\":\"Lazy iterators in PHP and Python - Blog of Jeroen De Dauw\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.entropywins.wtf\\\/blog\\\/#website\"},\"datePublished\":\"2015-08-19T19:37:33+00:00\",\"dateModified\":\"2018-08-19T02:20:40+00:00\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.entropywins.wtf\\\/blog\\\/2015\\\/08\\\/19\\\/lazy-iterators-in-php-and-python\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/www.entropywins.wtf\\\/blog\\\/2015\\\/08\\\/19\\\/lazy-iterators-in-php-and-python\\\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/www.entropywins.wtf\\\/blog\\\/2015\\\/08\\\/19\\\/lazy-iterators-in-php-and-python\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/www.entropywins.wtf\\\/blog\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Lazy iterators in PHP and Python\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/www.entropywins.wtf\\\/blog\\\/#website\",\"url\":\"https:\\\/\\\/www.entropywins.wtf\\\/blog\\\/\",\"name\":\"Entropy Wins\",\"description\":\"A blog on Software Architecture, Design and Craftsmanship\",\"publisher\":{\"@id\":\"https:\\\/\\\/www.entropywins.wtf\\\/blog\\\/#\\\/schema\\\/person\\\/4e2ef14f2ca7dc3a0ac137d1692b66b7\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/www.entropywins.wtf\\\/blog\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":[\"Person\",\"Organization\"],\"@id\":\"https:\\\/\\\/www.entropywins.wtf\\\/blog\\\/#\\\/schema\\\/person\\\/4e2ef14f2ca7dc3a0ac137d1692b66b7\",\"name\":\"Jeroen\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/d62e6b5b8e332335cf17854fac850d9c70ba367c4692872613c3110ebd4e009b?s=96&d=mm&r=g\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/d62e6b5b8e332335cf17854fac850d9c70ba367c4692872613c3110ebd4e009b?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/d62e6b5b8e332335cf17854fac850d9c70ba367c4692872613c3110ebd4e009b?s=96&d=mm&r=g\",\"caption\":\"Jeroen\"},\"logo\":{\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/d62e6b5b8e332335cf17854fac850d9c70ba367c4692872613c3110ebd4e009b?s=96&d=mm&r=g\"},\"sameAs\":[\"https:\\\/\\\/www.linkedin.com\\\/in\\\/jeroendedauw\\\/\",\"https:\\\/\\\/x.com\\\/https:\\\/\\\/twitter.com\\\/JeroenDeDauw\"]}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Lazy iterators in PHP and Python - Blog of Jeroen De Dauw","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.entropywins.wtf\/blog\/2015\/08\/19\/lazy-iterators-in-php-and-python\/","og_locale":"en_US","og_type":"article","og_title":"Lazy iterators in PHP and Python - Blog of Jeroen De Dauw","og_description":"I recently watched Clean Code Episode 34: Pattern Apocalypse, which is about several design patterns, including the Iterator. Afterwards I&hellip;","og_url":"https:\/\/www.entropywins.wtf\/blog\/2015\/08\/19\/lazy-iterators-in-php-and-python\/","og_site_name":"Blog of Jeroen De Dauw","article_published_time":"2015-08-19T19:37:33+00:00","article_modified_time":"2018-08-19T02:20:40+00:00","author":"Jeroen","twitter_card":"summary_large_image","twitter_creator":"@https:\/\/twitter.com\/JeroenDeDauw","twitter_site":"@JeroenDeDauw","twitter_misc":{"Written by":"Jeroen","Est. reading time":"9 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.entropywins.wtf\/blog\/2015\/08\/19\/lazy-iterators-in-php-and-python\/#article","isPartOf":{"@id":"https:\/\/www.entropywins.wtf\/blog\/2015\/08\/19\/lazy-iterators-in-php-and-python\/"},"author":{"name":"Jeroen","@id":"https:\/\/www.entropywins.wtf\/blog\/#\/schema\/person\/4e2ef14f2ca7dc3a0ac137d1692b66b7"},"headline":"Lazy iterators in PHP and Python","datePublished":"2015-08-19T19:37:33+00:00","dateModified":"2018-08-19T02:20:40+00:00","mainEntityOfPage":{"@id":"https:\/\/www.entropywins.wtf\/blog\/2015\/08\/19\/lazy-iterators-in-php-and-python\/"},"wordCount":1452,"commentCount":6,"publisher":{"@id":"https:\/\/www.entropywins.wtf\/blog\/#\/schema\/person\/4e2ef14f2ca7dc3a0ac137d1692b66b7"},"keywords":["Clean Code","Design patterns","Generators","Higher order functions","Iterator","Lazy evaluation","Lessons learned","PHP","Python"],"articleSection":["Programming"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.entropywins.wtf\/blog\/2015\/08\/19\/lazy-iterators-in-php-and-python\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.entropywins.wtf\/blog\/2015\/08\/19\/lazy-iterators-in-php-and-python\/","url":"https:\/\/www.entropywins.wtf\/blog\/2015\/08\/19\/lazy-iterators-in-php-and-python\/","name":"Lazy iterators in PHP and Python - Blog of Jeroen De Dauw","isPartOf":{"@id":"https:\/\/www.entropywins.wtf\/blog\/#website"},"datePublished":"2015-08-19T19:37:33+00:00","dateModified":"2018-08-19T02:20:40+00:00","breadcrumb":{"@id":"https:\/\/www.entropywins.wtf\/blog\/2015\/08\/19\/lazy-iterators-in-php-and-python\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.entropywins.wtf\/blog\/2015\/08\/19\/lazy-iterators-in-php-and-python\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/www.entropywins.wtf\/blog\/2015\/08\/19\/lazy-iterators-in-php-and-python\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.entropywins.wtf\/blog\/"},{"@type":"ListItem","position":2,"name":"Lazy iterators in PHP and Python"}]},{"@type":"WebSite","@id":"https:\/\/www.entropywins.wtf\/blog\/#website","url":"https:\/\/www.entropywins.wtf\/blog\/","name":"Entropy Wins","description":"A blog on Software Architecture, Design and Craftsmanship","publisher":{"@id":"https:\/\/www.entropywins.wtf\/blog\/#\/schema\/person\/4e2ef14f2ca7dc3a0ac137d1692b66b7"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.entropywins.wtf\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":["Person","Organization"],"@id":"https:\/\/www.entropywins.wtf\/blog\/#\/schema\/person\/4e2ef14f2ca7dc3a0ac137d1692b66b7","name":"Jeroen","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/secure.gravatar.com\/avatar\/d62e6b5b8e332335cf17854fac850d9c70ba367c4692872613c3110ebd4e009b?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/d62e6b5b8e332335cf17854fac850d9c70ba367c4692872613c3110ebd4e009b?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/d62e6b5b8e332335cf17854fac850d9c70ba367c4692872613c3110ebd4e009b?s=96&d=mm&r=g","caption":"Jeroen"},"logo":{"@id":"https:\/\/secure.gravatar.com\/avatar\/d62e6b5b8e332335cf17854fac850d9c70ba367c4692872613c3110ebd4e009b?s=96&d=mm&r=g"},"sameAs":["https:\/\/www.linkedin.com\/in\/jeroendedauw\/","https:\/\/x.com\/https:\/\/twitter.com\/JeroenDeDauw"]}]}},"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_shortlink":"https:\/\/wp.me\/p74TBF-ny","jetpack-related-posts":[{"id":1629,"url":"https:\/\/www.entropywins.wtf\/blog\/2016\/02\/22\/missing-in-php7-collections\/","url_meta":{"origin":1460,"position":0},"title":"Missing in PHP7: Collections","author":"Jeroen","date":"2016-02-22","format":false,"excerpt":"This is the fourth post in my Missing in PHP7 series. The previous one is about Value Objects. In this post I'll outline some problems PHP has with regards to collections, the implications of those problems, and a few mitigation strategies. PHP arrays PHPs main collection type is the associative\u2026","rel":"","context":"In &quot;Programming&quot;","block_context":{"text":"Programming","link":"https:\/\/www.entropywins.wtf\/blog\/category\/programming\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/www.entropywins.wtf\/blog\/wp-content\/uploads\/2016\/02\/dfp.jpg?resize=350%2C200&ssl=1","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/www.entropywins.wtf\/blog\/wp-content\/uploads\/2016\/02\/dfp.jpg?resize=350%2C200&ssl=1 1x, https:\/\/i0.wp.com\/www.entropywins.wtf\/blog\/wp-content\/uploads\/2016\/02\/dfp.jpg?resize=525%2C300&ssl=1 1.5x, https:\/\/i0.wp.com\/www.entropywins.wtf\/blog\/wp-content\/uploads\/2016\/02\/dfp.jpg?resize=700%2C400&ssl=1 2x"},"classes":[]},{"id":2106,"url":"https:\/\/www.entropywins.wtf\/blog\/2017\/10\/16\/introduction-to-iterators-and-generators-in-php\/","url_meta":{"origin":1460,"position":1},"title":"Introduction to Iterators and Generators in PHP","author":"Jeroen","date":"2017-10-16","format":false,"excerpt":"In this post I demonstrate an effective way to create iterators and generators in PHP and provide an example of a scenario in which using them makes sense. Generators have been around since PHP 5.5, and iterators have been around since the Planck epoch. Even so, a lot of PHP\u2026","rel":"","context":"In &quot;Programming&quot;","block_context":{"text":"Programming","link":"https:\/\/www.entropywins.wtf\/blog\/category\/programming\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/www.entropywins.wtf\/blog\/wp-content\/uploads\/2017\/10\/D8Pl1XwX4AEaU5H.jpeg?resize=350%2C200&ssl=1","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/www.entropywins.wtf\/blog\/wp-content\/uploads\/2017\/10\/D8Pl1XwX4AEaU5H.jpeg?resize=350%2C200&ssl=1 1x, https:\/\/i0.wp.com\/www.entropywins.wtf\/blog\/wp-content\/uploads\/2017\/10\/D8Pl1XwX4AEaU5H.jpeg?resize=525%2C300&ssl=1 1.5x, https:\/\/i0.wp.com\/www.entropywins.wtf\/blog\/wp-content\/uploads\/2017\/10\/D8Pl1XwX4AEaU5H.jpeg?resize=700%2C400&ssl=1 2x, https:\/\/i0.wp.com\/www.entropywins.wtf\/blog\/wp-content\/uploads\/2017\/10\/D8Pl1XwX4AEaU5H.jpeg?resize=1050%2C600&ssl=1 3x, https:\/\/i0.wp.com\/www.entropywins.wtf\/blog\/wp-content\/uploads\/2017\/10\/D8Pl1XwX4AEaU5H.jpeg?resize=1400%2C800&ssl=1 4x"},"classes":[]},{"id":1479,"url":"https:\/\/www.entropywins.wtf\/blog\/2015\/11\/08\/rewindable-php-generators\/","url_meta":{"origin":1460,"position":2},"title":"Rewindable PHP Generators","author":"Jeroen","date":"2015-11-08","format":false,"excerpt":"Today I was refactoring some code in one of my libraries, and ended up replacing a named Iterator class with a Generator. To my surprise this changed behaviour, which I noticed due to a broken test. A test verifying that I could iterate multiple times through the iterator - good\u2026","rel":"","context":"In &quot;Programming&quot;","block_context":{"text":"Programming","link":"https:\/\/www.entropywins.wtf\/blog\/category\/programming\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":1372,"url":"https:\/\/www.entropywins.wtf\/blog\/2014\/07\/14\/some-fun-with-iterators\/","url_meta":{"origin":1460,"position":3},"title":"Some fun with iterators","author":"Jeroen","date":"2014-07-14","format":false,"excerpt":"Sometimes you need to loop over a big pile of stuff and execute an action for each item. In the Wikibase software, this for instance occurs when we want to rebuild or refresh a part of our secondary persistence, or when we want to create an export of sorts. Historically\u2026","rel":"","context":"In &quot;Programming&quot;","block_context":{"text":"Programming","link":"https:\/\/www.entropywins.wtf\/blog\/category\/programming\/"},"img":{"alt_text":"tweetiterator","src":"https:\/\/i0.wp.com\/www.entropywins.wtf\/blog\/wp-content\/uploads\/2014\/07\/tweetiterator.jpg?resize=350%2C200&ssl=1","width":350,"height":200},"classes":[]},{"id":1484,"url":"https:\/\/www.entropywins.wtf\/blog\/2015\/11\/08\/wikidata-wikibase-json-dump-reader\/","url_meta":{"origin":1460,"position":4},"title":"Wikidata\/Wikibase Json Dump Reader","author":"Jeroen","date":"2015-11-08","format":false,"excerpt":"I've created a small PHP library to read from, and iterate through, Wikidata\/Wikibase JSON dumps. Wikidata is the free knowledge base that anyone can edit, and serves as a central data repository for Wikipedia and associated projects. Wikibase is a set of free open source software that powers Wikidata. You\u2026","rel":"","context":"In &quot;Programming&quot;","block_context":{"text":"Programming","link":"https:\/\/www.entropywins.wtf\/blog\/category\/programming\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":2092,"url":"https:\/\/www.entropywins.wtf\/blog\/2017\/10\/09\/yield-in-phpunit-data-providers\/","url_meta":{"origin":1460,"position":5},"title":"Yield in PHPUnit data providers","author":"Jeroen","date":"2017-10-09","format":false,"excerpt":"Initially I started creating a general post about PHP Generators, a feature introduced in PHP 5.5. However since I keep failing to come up with good examples for some cool ways to use Generators, I decided to do this mini post focusing on one such cool usage. PHPUnit data providers\u2026","rel":"","context":"In &quot;Programming&quot;","block_context":{"text":"Programming","link":"https:\/\/www.entropywins.wtf\/blog\/category\/programming\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]}],"jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/www.entropywins.wtf\/blog\/wp-json\/wp\/v2\/posts\/1460","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.entropywins.wtf\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.entropywins.wtf\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.entropywins.wtf\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.entropywins.wtf\/blog\/wp-json\/wp\/v2\/comments?post=1460"}],"version-history":[{"count":5,"href":"https:\/\/www.entropywins.wtf\/blog\/wp-json\/wp\/v2\/posts\/1460\/revisions"}],"predecessor-version":[{"id":2316,"href":"https:\/\/www.entropywins.wtf\/blog\/wp-json\/wp\/v2\/posts\/1460\/revisions\/2316"}],"wp:attachment":[{"href":"https:\/\/www.entropywins.wtf\/blog\/wp-json\/wp\/v2\/media?parent=1460"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.entropywins.wtf\/blog\/wp-json\/wp\/v2\/categories?post=1460"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.entropywins.wtf\/blog\/wp-json\/wp\/v2\/tags?post=1460"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}