<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>python on Arunrocks</title>
    <link>https://arunrocks.com/tags/python/</link>
    <description>Recent articles in python on Arunrocks</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en-us</language>
    <lastBuildDate>Tue, 23 Mar 2021 12:22:02 +0530</lastBuildDate><atom:link href="https://arunrocks.com/tags/python/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Print from 1 to 100 without loops or numbers in Python</title>
      <link>https://arunrocks.com/print-from-1-to-100-without-loops-or-numbers-in-python/</link>
      <pubDate>Tue, 23 Mar 2021 12:22:02 +0530</pubDate>
      
      <guid>https://arunrocks.com/print-from-1-to-100-without-loops-or-numbers-in-python/</guid>
      <description>&lt;p&gt;A new programming problem has been trending recently - write a program to print numbers from one to hundred without using any loops or mentioning numbers in the source. Naturally, I was interested in a solution in Python.&lt;/p&gt;
&lt;p&gt;I got many brilliant answers on Twitter. But first let me show you how I approached it. I was looking for a general and readable solution than the shortest one. My thought process was &amp;ndash; even if we cannot mention numbers we can convert non-numeric types to numbers. So I tried with Booleans and Strings:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;n&#34;&gt;zero&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;int&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;bp&#34;&gt;False&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;one&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;int&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;bp&#34;&gt;True&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;hundred&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;int&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;f&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;{one}{zero}{zero}&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;


&lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;shownum&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;
    &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;hundred&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
        &lt;span class=&#34;k&#34;&gt;print&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
        &lt;span class=&#34;n&#34;&gt;shownum&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;one&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;


&lt;span class=&#34;n&#34;&gt;shownum&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;one&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Starting from scratch, we get 0 and 1 from the False and True values. Then to create 100,  the upper limit of the loop, we use the new favourite string interpolation method &amp;ndash; f-strings.&lt;/p&gt;
&lt;p&gt;Overcoming the limitation of not using loops was quite straightforward - just use Recursion. We have to be careful though, Python does not have Tail Call Optimization (since &lt;a href=&#34;http://neopythonic.blogspot.com/2009/04/final-words-on-tail-calls.html&#34;&gt;Guido prefers&lt;/a&gt; to have proper tracebacks), so if you keep increasing the upper limit of the loop you will end up in a stack overflow.&lt;/p&gt;
&lt;h3 id=&#34;whiz-kids-on-twitter&#34;&gt;Whiz kids on Twitter&lt;/h3&gt;
&lt;p&gt;To my &lt;a href=&#34;https://twitter.com/arocks/status/1373977341630631943&#34;&gt;poser tweet&lt;/a&gt; yesterday, there were many wonderful solutions that were way shorter than mine. Here are some of them:&lt;/p&gt;
&lt;h4 id=&#34;the-long-scream-by-abhiram&#34;&gt;The Long Scream by Abhiram&lt;/h4&gt;
&lt;blockquote class=&#34;twitter-tweet&#34;&gt;&lt;p lang=&#34;hu&#34; dir=&#34;ltr&#34;&gt;print([*range(len(&amp;#39;a&amp;#39;), len(&amp;#39;aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa&amp;#39;))])&lt;br&gt;😂&lt;/p&gt;&amp;mdash; Abhiram R (@abhicantdraw) &lt;a href=&#34;https://twitter.com/abhicantdraw/status/1373980664022716420?ref_src=twsrc%5Etfw&#34;&gt;March 22, 2021&lt;/a&gt;&lt;/blockquote&gt;
&lt;script async src=&#34;https://platform.twitter.com/widgets.js&#34; charset=&#34;utf-8&#34;&gt;&lt;/script&gt;

&lt;p&gt;What I like here is the clever use of the * operator to convert the range object into a list tersely. And of course the liberal use of the &amp;ldquo;a&amp;rdquo;-s that just screams &amp;ldquo;I cannot be unseen&amp;rdquo;.&lt;/p&gt;
&lt;h4 id=&#34;short-and-succinct-by-rohan&#34;&gt;Short and Succinct by Rohan&lt;/h4&gt;
&lt;blockquote class=&#34;twitter-tweet&#34;&gt;&lt;p lang=&#34;en&#34; dir=&#34;ltr&#34;&gt;list(map(int,range(ord(b&amp;quot;e&amp;quot;))))&lt;/p&gt;&amp;mdash; Rohan Verma (@rhnvrm) &lt;a href=&#34;https://twitter.com/rhnvrm/status/1373997260548177920?ref_src=twsrc%5Etfw&#34;&gt;March 22, 2021&lt;/a&gt;&lt;/blockquote&gt;
&lt;script async src=&#34;https://platform.twitter.com/widgets.js&#34; charset=&#34;utf-8&#34;&gt;&lt;/script&gt;

&lt;p&gt;Cleverly taking advantage of Python&amp;rsquo;s built-in &lt;code&gt;ord&lt;/code&gt; function to get the &lt;a href=&#34;https://www.asciitable.com/&#34;&gt;ASCII code&lt;/a&gt; of lower case &amp;lsquo;e&amp;rsquo; (it is 101 not 100), we sort of have a code-golf winner. Sort of because it starts count from 0 not 1 as the original question posed. But this is Twitter, a correction soon emerged.&lt;/p&gt;
&lt;p&gt;Note that the map and int functions are not really required here, making it even more shorter! In a direct message Rohan shared an improved solution that starts counting from one:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;nb&#34;&gt;list&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;filter&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;lambda&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;x&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;x&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;range&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;ord&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;sa&#34;&gt;b&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;e&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;evolved-by-anirudh&#34;&gt;Evolved by Anirudh&lt;/h4&gt;
&lt;blockquote class=&#34;twitter-tweet&#34;&gt;&lt;p lang=&#34;fr&#34; dir=&#34;ltr&#34;&gt;list(range(ord(&amp;#39;a&amp;#39;)-ord(&amp;#39;a&amp;#39;), ord(&amp;#39;e&amp;#39;)))&lt;/p&gt;&amp;mdash; Anirudh Menon (@anikmenon) &lt;a href=&#34;https://twitter.com/anikmenon/status/1374211531060113416?ref_src=twsrc%5Etfw&#34;&gt;March 23, 2021&lt;/a&gt;&lt;/blockquote&gt;
&lt;script async src=&#34;https://platform.twitter.com/widgets.js&#34; charset=&#34;utf-8&#34;&gt;&lt;/script&gt;

&lt;p&gt;With a minor correction, this code fixes the start count to 1. As a nice touch the strings form &amp;lsquo;bae&amp;rsquo; which must be the cutest term for a friend.&lt;/p&gt;
&lt;h4 id=&#34;can-this-get-shorter-by-arun&#34;&gt;Can This Get Shorter by Arun&lt;/h4&gt;
&lt;p&gt;With the benefit of having seen all the ideas, I can finally put forth my shortest solution (with 23 characters):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;range&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;bp&#34;&gt;True&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;ord&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;e&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;So that&amp;rsquo;s the end of this code golf for me. That is, until someone else comes up with something shorter!&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Fitting a Django Application in One File</title>
      <link>https://arunrocks.com/django-application-in-one-file/</link>
      <pubDate>Wed, 09 Dec 2020 22:54:50 +0530</pubDate>
      
      <guid>https://arunrocks.com/django-application-in-one-file/</guid>
      <description>&lt;p&gt;Earlier this week, Anthony a french economics university student wanted to talk to me over Zoom about my &lt;a href=&#34;https://arunrocks.com/ray-tracer-in-python-1-points-in-3d-space-show-notes/&#34;&gt;ray tracer tutorials&lt;/a&gt;. He and his friend were new to Python but were excited to implement their own ray tracer after following my videos. One of the questions that popped up in the conversation was - &amp;ldquo;Can we put all the classes in one file instead of breaking it into individual files per class?&amp;rdquo;. I said, &amp;ldquo;Of course&amp;rdquo; and noticed a wave of relief in their faces. In fact, I explained, my earlier implementation was all in one file and later broken up for better pedagogy.&lt;/p&gt;
&lt;div data-pullquote=&#34;&amp;#34;It might be amusing to some Django developers that we will not start with the startproject command.&#34;&gt;
&lt;/div&gt;
&lt;p&gt;But the charm of an entire project in a single file is compelling. I remember seeing a Sinatra web application a few years ago containing the entire application and assets like HTML templates and CSS in a single file. Presenting all the components in the same file gave a complete high-level overview of the project by simply scrolling up and down.&lt;/p&gt;
&lt;p&gt;Normally, at this point, someone would suggest a microframework. But it is not that easy.&lt;/p&gt;
&lt;h2 id=&#34;microframeworks&#34;&gt;Microframeworks&lt;/h2&gt;
&lt;p&gt;Microframeworks take a minimalistic approach by omitting certain components or directing you to a few recommended components. For instance, &lt;a href=&#34;https://bottlepy.org/docs/dev/&#34;&gt;Bottle&lt;/a&gt; contains basic form handling capabilities but has no protection against &lt;a href=&#34;https://www.wikiwand.com/en/Cross-site_request_forgery&#34;&gt;CSRF&lt;/a&gt; or &lt;a href=&#34;https://www.wikiwand.com/en/Clickjacking&#34;&gt;clickjacking&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;So the approach is generally to use another library like &lt;a href=&#34;https://pypi.org/project/bottle-utils-csrf/&#34;&gt;bottle-utils-csrf&lt;/a&gt;. This leaves the task of integration to the developer. This is not to pooh-pooh tiny web frameworks. I love the idea (especially Bottle which I think is really cute). But for public facing sites, I prefer the safety and convenience of Django.&lt;/p&gt;
&lt;p&gt;So I am tempted to try this one-file trick in Django. Let’s try to make a non-trivial web application with forms, templates and images. How does one go about doing something like that?&lt;/p&gt;
&lt;p&gt;Note: if you prefer to watch the video version, click on the video below:&lt;/p&gt;

&lt;div style=&#34;position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;&#34;&gt;
  &lt;iframe src=&#34;https://www.youtube.com/embed/7XNChGGoBf0&#34; style=&#34;position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;&#34; allowfullscreen title=&#34;YouTube Video&#34;&gt;&lt;/iframe&gt;
&lt;/div&gt;

&lt;h2 id=&#34;django-applications-in-one-file&#34;&gt;Django Applications in One File&lt;/h2&gt;
&lt;h3 id=&#34;minimal&#34;&gt;Minimal&lt;/h3&gt;
&lt;p&gt;Let’s start small by creating a minimal Hello World application in Django. It might be amusing to some Django developers that we will not start with the &lt;code&gt;startproject&lt;/code&gt; command. In fact, it is not necessary for Django to work at all. All that initial directory structure and files like settings.py are for your convenience.&lt;/p&gt;
&lt;p&gt;First, create a simple file called &lt;code&gt;app.py&lt;/code&gt; with the following:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;sys&lt;/span&gt;

&lt;span class=&#34;kn&#34;&gt;from&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;django.conf&lt;/span&gt; &lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;settings&lt;/span&gt;
&lt;span class=&#34;kn&#34;&gt;from&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;django.urls&lt;/span&gt; &lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;path&lt;/span&gt;
&lt;span class=&#34;kn&#34;&gt;from&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;django.http&lt;/span&gt; &lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;HttpResponse&lt;/span&gt;

&lt;span class=&#34;n&#34;&gt;settings&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;configure&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;
	&lt;span class=&#34;n&#34;&gt;DEBUG&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;bp&#34;&gt;True&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;# For debugging&lt;/span&gt;
	&lt;span class=&#34;n&#34;&gt;SECRET_KEY&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;a-bad-secret&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;# Insecure! change this&lt;/span&gt;
	&lt;span class=&#34;n&#34;&gt;ROOT_URLCONF&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;vm&#34;&gt;__name__&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;


&lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;home&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;request&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;HttpResponse&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;Welcome!&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;


&lt;span class=&#34;n&#34;&gt;urlpatterns&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;
	&lt;span class=&#34;n&#34;&gt;path&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;home&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;

&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;vm&#34;&gt;__name__&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;__main__&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
	&lt;span class=&#34;kn&#34;&gt;from&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;django.core.management&lt;/span&gt; &lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;execute_from_command_line&lt;/span&gt;

	&lt;span class=&#34;n&#34;&gt;execute_from_command_line&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;sys&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;argv&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Yes, that&amp;rsquo;s all you need. There are some bad practices like hard coding the secret key (easily fixed). But the sheer elegance of everything being in hardly a screenful is quite rewarding.&lt;/p&gt;
&lt;p&gt;The command to run this file is: &lt;code&gt;python app.py runserver 8080&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Now we will skip a couple of steps (they are in the video) and move on to a simple &amp;ldquo;Coming Soon&amp;rdquo; landing page.&lt;/p&gt;
&lt;h3 id=&#34;coming-soon-application&#34;&gt;Coming Soon Application&lt;/h3&gt;
&lt;p&gt;The idea of a coming-soon page is to gauge interest in a product before it is released. Such pages must have a clear call to action (CTA) like asking for your email. Ideally it should have minimum friction and yet collect all the relevant information.&lt;/p&gt;
&lt;p&gt;Let’s look at my updated app.py:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;os&lt;/span&gt;
&lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;sys&lt;/span&gt;

&lt;span class=&#34;kn&#34;&gt;from&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;django.conf&lt;/span&gt; &lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;settings&lt;/span&gt;
&lt;span class=&#34;kn&#34;&gt;from&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;django.urls&lt;/span&gt; &lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;path&lt;/span&gt;
&lt;span class=&#34;kn&#34;&gt;from&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;django.http&lt;/span&gt; &lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;HttpResponse&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;HttpResponseRedirect&lt;/span&gt;
&lt;span class=&#34;kn&#34;&gt;from&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;django.core.wsgi&lt;/span&gt; &lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;get_wsgi_application&lt;/span&gt;
&lt;span class=&#34;kn&#34;&gt;from&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;django.template&lt;/span&gt; &lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;RequestContext&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Template&lt;/span&gt;
&lt;span class=&#34;kn&#34;&gt;from&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;django&lt;/span&gt; &lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;forms&lt;/span&gt;

&lt;span class=&#34;n&#34;&gt;CSV_LIST&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;thelist.csv&amp;#34;&lt;/span&gt;

&lt;span class=&#34;n&#34;&gt;settings&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;configure&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;
	&lt;span class=&#34;n&#34;&gt;DEBUG&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;os&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;environ&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;get&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;DEBUG&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;1&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt;
	&lt;span class=&#34;n&#34;&gt;ALLOWED_HOSTS&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;*&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;],&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;# Disable host header validation&lt;/span&gt;
	&lt;span class=&#34;n&#34;&gt;ROOT_URLCONF&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;vm&#34;&gt;__name__&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
	&lt;span class=&#34;n&#34;&gt;SECRET_KEY&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;os&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;environ&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;get&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;SECRET_KEY&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;a-bad-secret&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt;
	&lt;span class=&#34;n&#34;&gt;TEMPLATES&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[{&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;BACKEND&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;django.template.backends.django.DjangoTemplates&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}],&lt;/span&gt;
	&lt;span class=&#34;n&#34;&gt;MIDDLEWARE_CLASSES&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;
    	&lt;span class=&#34;s2&#34;&gt;&amp;#34;django.middleware.common.CommonMiddleware&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
    	&lt;span class=&#34;s2&#34;&gt;&amp;#34;django.middleware.csrf.CsrfViewMiddleware&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
    	&lt;span class=&#34;s2&#34;&gt;&amp;#34;django.middleware.clickjacking.XFrameOptionsMiddleware&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
	&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;


&lt;span class=&#34;k&#34;&gt;class&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;EnlistForm&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;forms&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Form&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;
	&lt;span class=&#34;n&#34;&gt;email&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;forms&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;EmailField&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;
    	&lt;span class=&#34;n&#34;&gt;required&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;bp&#34;&gt;True&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
    	&lt;span class=&#34;n&#34;&gt;label&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;bp&#34;&gt;False&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
    	&lt;span class=&#34;n&#34;&gt;widget&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;forms&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;EmailInput&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;attrs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;placeholder&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Email&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}),&lt;/span&gt;
	&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
	&lt;span class=&#34;n&#34;&gt;referrer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;forms&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;CharField&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;required&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;bp&#34;&gt;False&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;widget&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;forms&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;HiddenInput&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;())&lt;/span&gt;


&lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;home&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;request&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;request&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;method&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;POST&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
    	&lt;span class=&#34;n&#34;&gt;form&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;EnlistForm&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;request&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;POST&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
    	&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;form&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;is_valid&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;():&lt;/span&gt;
        	&lt;span class=&#34;n&#34;&gt;email&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;form&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;cleaned_data&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;email&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
        	&lt;span class=&#34;n&#34;&gt;referrer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;form&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;cleaned_data&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;referrer&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
        	&lt;span class=&#34;n&#34;&gt;ip&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;request&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;META&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;get&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;REMOTE_ADDR&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
        	&lt;span class=&#34;k&#34;&gt;print&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;f&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;Got email of {email}&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
        	&lt;span class=&#34;k&#34;&gt;with&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;open&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;CSV_LIST&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;a&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;as&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;csv&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
            	&lt;span class=&#34;n&#34;&gt;csv&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;write&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;f&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;{email},{referrer},{ip}&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
        	&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;HttpResponseRedirect&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;/thanks/&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;else&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
    	&lt;span class=&#34;n&#34;&gt;form&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;EnlistForm&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;initial&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;referrer&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;request&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;META&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;get&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;HTTP_REFERER&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)})&lt;/span&gt;
	&lt;span class=&#34;n&#34;&gt;context&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;RequestContext&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;
    	&lt;span class=&#34;n&#34;&gt;request&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;content&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Sign up for early access&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;form&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;form&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
	&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;HttpResponse&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;MAIN_HTML&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;render&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;context&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;


&lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;thanks&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;request&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;
	&lt;span class=&#34;n&#34;&gt;context&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;RequestContext&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;
    	&lt;span class=&#34;n&#34;&gt;request&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
    	&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;content&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Thank you for signing up. We will contact you!&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;form&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;bp&#34;&gt;None&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;},&lt;/span&gt;
	&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
	&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;HttpResponse&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;MAIN_HTML&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;render&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;context&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;


&lt;span class=&#34;n&#34;&gt;urlpatterns&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;
	&lt;span class=&#34;n&#34;&gt;path&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;home&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt;
	&lt;span class=&#34;n&#34;&gt;path&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;thanks/&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;thanks&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;

&lt;span class=&#34;n&#34;&gt;app&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;get_wsgi_application&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;


&lt;span class=&#34;n&#34;&gt;MAIN_HTML&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Template&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;
	&lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&amp;#34;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;lt;html&amp;gt;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;  &amp;lt;head&amp;gt;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;	&amp;lt;title&amp;gt;Coming Soon | Flying Cars&amp;lt;/title&amp;gt;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;	&amp;lt;meta name=&amp;#34;viewport&amp;#34; content=&amp;#34;width=device-width, initial-scale=1.0&amp;#34;&amp;gt;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;	&amp;lt;style&amp;gt;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt; 	@import url(&amp;#39;https://fonts.googleapis.com/css2?family=Exo:wght@400;500;600;700;800;900&amp;amp;display=swap&amp;#39;);
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt; 	*{
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;   	margin: 0;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;   	padding: 0;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;   	box-sizing: border-box;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;   	font-family: &amp;#39;Exo&amp;#39;, sans-serif;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt; 	}
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt; 	html,body{
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;   	display: grid;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;   	height: 100%;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;   	width: 100%;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;   	place-items: center;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;   	background-color: #343434;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;   	/* Thanks to Hero Patterns for the background */
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;   	background-image: url(&amp;#34;data:image/svg+xml,%3Csvg xmlns=&amp;#39;http://www.w3.org/2000/svg&amp;#39; viewBox=&amp;#39;0 0 56 28&amp;#39; width=&amp;#39;56&amp;#39; height=&amp;#39;28&amp;#39;&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;%3E&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;%3Cpath fill=&amp;#39;%23000000&amp;#39; fill-opacity=&amp;#39;0.4&amp;#39; d=&amp;#39;M56 26v2h-7.75c2.3-1.27 4.94-2 7.75-2zm-26 2a2 2 0 1 0-4 0h-4.09A25.98 25.98 0 0 0 0 16v-2c.67 0 1.34.02 2 .07V14a2 2 0 0 0-2-2v-2a4 4 0 0 1 3.98 3.6 28.09 28.09 0 0 1 2.8-3.86A8 8 0 0 0 0 6V4a9.99 9.99 0 0 1 8.17 4.23c.94-.95 1.96-1.83 3.03-2.63A13.98 13.98 0 0 0 0 0h7.75c2 1.1 3.73 2.63 5.1 4.45 1.12-.72 2.3-1.37 3.53-1.93A20.1 20.1 0 0 0 14.28 0h2.7c.45.56.88 1.14 1.29 1.74 1.3-.48 2.63-.87 4-1.15-.11-.2-.23-.4-.36-.59H26v.07a28.4 28.4 0 0 1 4 0V0h4.09l-.37.59c1.38.28 2.72.67 4.01 1.15.4-.6.84-1.18 1.3-1.74h2.69a20.1 20.1 0 0 0-2.1 2.52c1.23.56 2.41 1.2 3.54 1.93A16.08 16.08 0 0 1 48.25 0H56c-4.58 0-8.65 2.2-11.2 5.6 1.07.8 2.09 1.68 3.03 2.63A9.99 9.99 0 0 1 56 4v2a8 8 0 0 0-6.77 3.74c1.03 1.2 1.97 2.5 2.79 3.86A4 4 0 0 1 56 10v2a2 2 0 0 0-2 2.07 28.4 28.4 0 0 1 2-.07v2c-9.2 0-17.3 4.78-21.91 12H30zM7.75 28H0v-2c2.81 0 5.46.73 7.75 2zM56 20v2c-5.6 0-10.65 2.3-14.28 6h-2.7c4.04-4.89 10.15-8 16.98-8zm-39.03 8h-2.69C10.65 24.3 5.6 22 0 22v-2c6.83 0 12.94 3.11 16.97 8zm15.01-.4a28.09 28.09 0 0 1 2.8-3.86 8 8 0 0 0-13.55 0c1.03 1.2 1.97 2.5 2.79 3.86a4 4 0 0 1 7.96 0zm14.29-11.86c1.3-.48 2.63-.87 4-1.15a25.99 25.99 0 0 0-44.55 0c1.38.28 2.72.67 4.01 1.15a21.98 21.98 0 0 1 36.54 0zm-5.43 2.71c1.13-.72 2.3-1.37 3.54-1.93a19.98 19.98 0 0 0-32.76 0c1.23.56 2.41 1.2 3.54 1.93a15.98 15.98 0 0 1 25.68 0zm-4.67 3.78c.94-.95 1.96-1.83 3.03-2.63a13.98 13.98 0 0 0-22.4 0c1.07.8 2.09 1.68 3.03 2.63a9.99 9.99 0 0 1 16.34 0z&amp;#39;&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;%3E&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;%3C/path&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;%3E&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;%3C/svg&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;%3E&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;);
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt; 	}
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt; 	::selection{
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;   	color: #fff;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;   	background: #FC4782;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt; 	}
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt; 	.wrapper{
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;   	color: #eee;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;   	max-width: 900px;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;   	text-align: center;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;   	padding: 0 50px;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt; 	}
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt; 	.signup {
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;   	margin-top: 30px;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;   	margin-bottom: 10px;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt; 	}
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt; 	.content {
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;   	margin-top: 40px;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;   	margin-bottom: 10px;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt; 	}
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;	&amp;lt;/style&amp;gt;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;  &amp;lt;/head&amp;gt;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;  &amp;lt;body&amp;gt;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;	&amp;lt;div class=&amp;#34;wrapper&amp;#34;&amp;gt;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;  	&amp;lt;svg width=&amp;#34;600&amp;#34; height=&amp;#34;300&amp;#34; version=&amp;#34;1.1&amp;#34; viewBox=&amp;#34;0 0 600 300&amp;#34; xmlns=&amp;#34;http://www.w3.org/2000/svg&amp;#34;&amp;gt;&amp;lt;g transform=&amp;#34;translate(0,312)&amp;#34;&amp;gt;&amp;lt;path d=&amp;#34;m218.36-289.66h163.29c29.039 0 52.417 23.378 52.417 52.417v45.564c0 29.039-23.378 52.417-52.417 52.417h-163.29c-29.039 0-52.417-23.378-52.417-52.417v-45.564c0-29.039 23.378-52.417 52.417-52.417z&amp;#34; fill=&amp;#34;#204a87&amp;#34; stop-color=&amp;#34;#000000&amp;#34; stroke=&amp;#34;#eeeeec&amp;#34; stroke-linecap=&amp;#34;round&amp;#34; stroke-linejoin=&amp;#34;round&amp;#34; stroke-width=&amp;#34;4&amp;#34;/&amp;gt;&amp;lt;g fill=&amp;#34;#729fcf&amp;#34; stroke=&amp;#34;#eeeeec&amp;#34; stroke-linejoin=&amp;#34;round&amp;#34; stroke-width=&amp;#34;4&amp;#34;&amp;gt;&amp;lt;path d=&amp;#34;m240.88-162.15c21.473-37.192 42.946-74.385 64.419-111.58&amp;#34; stop-color=&amp;#34;#000000&amp;#34;/&amp;gt;&amp;lt;g stroke-linecap=&amp;#34;round&amp;#34;&amp;gt;&amp;lt;path d=&amp;#34;m276.15-249.32h-72.081&amp;#34; stop-color=&amp;#34;#000000&amp;#34;/&amp;gt;&amp;lt;path d=&amp;#34;m259.9-221.32h-56.025&amp;#34; stop-color=&amp;#34;#000000&amp;#34;/&amp;gt;&amp;lt;path d=&amp;#34;m267.69-235.32h-63.714&amp;#34; stop-color=&amp;#34;#000000&amp;#34;/&amp;gt;&amp;lt;path d=&amp;#34;m370.37-162.15c-21.473-37.192-42.946-74.385-64.419-111.58&amp;#34; stop-color=&amp;#34;#000000&amp;#34;/&amp;gt;&amp;lt;path d=&amp;#34;m332-249.93h72.081&amp;#34; stop-color=&amp;#34;#000000&amp;#34;/&amp;gt;&amp;lt;path d=&amp;#34;m348.25-221.93h56.025&amp;#34; stop-color=&amp;#34;#000000&amp;#34;/&amp;gt;&amp;lt;path d=&amp;#34;m340.46-235.93h63.714&amp;#34; stop-color=&amp;#34;#000000&amp;#34;/&amp;gt;&amp;lt;path d=&amp;#34;m240.88-162.15c21.473-26.526 42.946-53.051 64.419-79.577&amp;#34; stop-color=&amp;#34;#000000&amp;#34;/&amp;gt;&amp;lt;/g&amp;gt;&amp;lt;path d=&amp;#34;m370.37-162.15c-21.473-26.526-42.946-53.051-64.419-79.577&amp;#34; stop-color=&amp;#34;#000000&amp;#34;/&amp;gt;&amp;lt;/g&amp;gt;&amp;lt;g fill=&amp;#34;#eeeeec&amp;#34;&amp;gt;&amp;lt;path d=&amp;#34;m183.74-116.06-6.3858 17.316h12.795zm-2.6568-4.6378h5.337l13.261 34.795h-4.8942l-3.1696-8.9261h-15.685l-3.1696 8.9261h-4.9641z&amp;#34; style=&amp;#34;text-decoration-color:#000000;text-decoration-line:none&amp;#34;/&amp;gt;&amp;lt;path d=&amp;#34;m222.66-120.7h4.7078v34.795h-4.7078z&amp;#34; style=&amp;#34;text-decoration-color:#000000;text-decoration-line:none&amp;#34;/&amp;gt;&amp;lt;path d=&amp;#34;m271.14-102.22q1.5149.51273 2.9365 2.1907 1.445 1.678 2.8899 4.6145l4.7777 9.5087h-5.0573l-4.4514-8.9261q-1.7246-3.4959-3.356-4.6378-1.6081-1.142-4.4048-1.142h-5.1273v14.706h-4.7078v-34.795h10.627q5.9663 0 8.9028 2.4937t2.9365 7.5278q0 3.2861-1.5382 5.4535-1.5149 2.1674-4.4281 3.0064zm-11.793-14.613v12.352h5.9196q3.4026 0 5.1273-1.5615 1.7479-1.5848 1.7479-4.6378t-1.7479-4.5912q-1.7246-1.5615-5.1273-1.5615z&amp;#34; style=&amp;#34;text-decoration-color:#000000;text-decoration-line:none&amp;#34;/&amp;gt;&amp;lt;path d=&amp;#34;m329.38-118.02v4.9641q-2.3772-2.214-5.0806-3.3094-2.6802-1.0954-5.7099-1.0954-5.9663 0-9.1358 3.659-3.1696 3.6357-3.1696 10.534 0 6.8752 3.1696 10.534 3.1696 3.6357 9.1358 3.6357 3.0297 0 5.7099-1.0954 2.7035-1.0954 5.0806-3.3094v4.9175q-2.4704 1.678-5.2438 2.517-2.7501.83901-5.8264.83901-7.9006 0-12.445-4.8243-4.5446-4.8476-4.5446-13.214 0-8.39 4.5446-13.214 4.5446-4.8476 12.445-4.8476 3.123 0 5.873.839 2.7734.8157 5.1972 2.4704z&amp;#34; style=&amp;#34;text-decoration-color:#000000;text-decoration-line:none&amp;#34;/&amp;gt;&amp;lt;path d=&amp;#34;m366.18-116.06-6.3858 17.316h12.795zm-2.6568-4.6378h5.337l13.261 34.795h-4.8942l-3.1696-8.9261h-15.685l-3.1696 8.9261h-4.9641z&amp;#34; style=&amp;#34;text-decoration-color:#000000;text-decoration-line:none&amp;#34;/&amp;gt;&amp;lt;path d=&amp;#34;m421.6-102.22q1.5149.51273 2.9365 2.1907 1.445 1.678 2.8899 4.6145l4.7777 9.5087h-5.0573l-4.4514-8.9261q-1.7246-3.4959-3.356-4.6378-1.6081-1.142-4.4048-1.142h-5.1272v14.706h-4.7078v-34.795h10.627q5.9663 0 8.9028 2.4937t2.9365 7.5278q0 3.2861-1.5382 5.4535-1.5149 2.1674-4.4281 3.0064zm-11.793-14.613v12.352h5.9196q3.4026 0 5.1272-1.5615 1.7479-1.5848 1.7479-4.6378t-1.7479-4.5912q-1.7246-1.5615-5.1272-1.5615z&amp;#34; style=&amp;#34;text-decoration-color:#000000;text-decoration-line:none&amp;#34;/&amp;gt;&amp;lt;/g&amp;gt;&amp;lt;/g&amp;gt;&amp;lt;/svg&amp;gt;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;  	&amp;lt;h1&amp;gt;All Your Traffic Problems Solved!&amp;lt;/h1&amp;gt;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;  	&amp;lt;h2&amp;gt;Feel the future with affordable levitating cars.&amp;lt;/h2&amp;gt;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;  	&amp;lt;div class=&amp;#34;content&amp;#34;&amp;gt;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;    	{{ content }}
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;    	{&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;% i&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;f form %}
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;      	&amp;lt;form action=&amp;#34;.&amp;#34; method=&amp;#34;post&amp;#34; class=&amp;#34;enlist_form&amp;#34;&amp;gt;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;        	{&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;% c&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;srf_token %}
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;        	{{ form.non_field_errors }}
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;        	{{ form.email.errors }}
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;        	{{ form.referrer }}
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;        	{{ form.referrer.errors }}
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;        	{{ form.email }}
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;        	&amp;lt;button type=&amp;#34;submit&amp;#34;&amp;gt;Add Me&amp;lt;/button&amp;gt;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;      	&amp;lt;/form&amp;gt;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;    	{&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;% e&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;ndif %}
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;  	&amp;lt;/div&amp;gt;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;	&amp;lt;/div&amp;gt;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;  &amp;lt;/body&amp;gt;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;lt;/html&amp;gt;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;


&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;vm&#34;&gt;__name__&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;__main__&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
	&lt;span class=&#34;kn&#34;&gt;from&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;django.core.management&lt;/span&gt; &lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;execute_from_command_line&lt;/span&gt;

	&lt;span class=&#34;n&#34;&gt;execute_from_command_line&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;sys&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;argv&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Except for the absence of individual files, most of the code should be familiar to a Django developer. There is a large HTML template (including two SVG images) embedded as a string.&lt;/p&gt;
&lt;p&gt;Note that I do not use the ORM here. Django does seem to need a directory structure for that (Unless any reader could show me how to do it in a single file).&lt;/p&gt;
&lt;p&gt;Hopefully this shows how minimal Django could be. You might be able to use your favourite framework in places which you didn’t think were possible.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Black Holes and Python</title>
      <link>https://arunrocks.com/blackholes-and-python/</link>
      <pubDate>Wed, 17 Apr 2019 10:14:36 +0530</pubDate>
      
      <guid>https://arunrocks.com/blackholes-and-python/</guid>
      <description>&lt;p&gt;&lt;figure&gt;
    &lt;img loading=&#34;lazy&#34; src=&#34;https://arunrocks.com/static/images/blog/blackholes-1.jpg&#34; alt=&#34;Black Hole at the center of M87 Galaxy&#34;  title=&#34;Black Hole in M87 - Image Courtesy: BBC&#34;  width=976 height=&#34;549&#34;  /&gt;
    &lt;figcaption&gt;Black Hole in M87 - Image Courtesy: BBC&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;The first picture of a black hole is probably one of the most exciting developments in the world of science. The blurry ring of fiery orange might not seem difficult to produce. In fact, it involved years of effort by an international team of scientists, including computer scientists.&lt;/p&gt;
&lt;p&gt;Reading the account, I am excited about the role Python played in this endeavour. This is interesting because when we talk about a scientific discovery we usually talk about the people - the scientists who made leaps of intuitions and found correlations that no one else had. But increasingly technology is playing a significant role in discoveries by sifting through enormous amounts of data and extracting valuable insights.&lt;/p&gt;
&lt;p&gt;Python&amp;rsquo;s popularity in the scientific computing would not be a surprise to most Python programmers today. But back in 2009 when I attended the &lt;a href=&#34;https://in.pycon.org/2009/&#34;&gt;first PyCon India&lt;/a&gt; in IISc Bangalore, I was surprised to see talks on experimental Physics and fluid simulations. When I asked &lt;a href=&#34;https://www.aero.iitb.ac.in/~prabhu/&#34;&gt;Prof Prabhu&lt;/a&gt; on why Python is so popular in scientific computing, he said &amp;ldquo;it is very accessible to us &amp;ndash; non-programmers&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;Casually browsing through the software used by the astronomers, you will find mentions of Python libraries like
Numpy, Scipy, Matplotlib, Pandas and Jupyter. Remarkably, entire projects such as &lt;a href=&#34;https://github.com/achael/eht-imaging/&#34;&gt;eht-python&lt;/a&gt; are written only in Python. Python is not just the language of choice, it is the lingua franca of scientific computing.&lt;/p&gt;
&lt;p&gt;Yet, if you think about it, there are better programming languages be it in terms of - speed, type safety or brevity. But Python overcomes these limitations and sometimes succeeds due to some pragmatic language design decisions.&lt;/p&gt;
&lt;h3 id=&#34;speed-can-be-delegated&#34;&gt;Speed Can Be Delegated&lt;/h3&gt;
&lt;p&gt;Ironically, plain Python code can perform very poorly for computation intensive tasks. But libraries like NumPy are de facto when it comes to any form of number crunching. It provides an N-dimensional array object with several high level operations like cross product or transpose. The C engine of the library accelerates these operations close to raw machine speed.&lt;/p&gt;
&lt;p&gt;In the early days of Python, it was expected that performance intensive parts would be written in other languages like C or FORTRAN and a wrapper interface would be used to invoke them. Over time, wealth of libraries like NumPy made it unnecessary to write any custom C code. Why reinvent the wheel when you can just &amp;ldquo;import&amp;rdquo; and use it?&lt;/p&gt;
&lt;h3 id=&#34;libraries-that-play-well&#34;&gt;Libraries that Play Well&lt;/h3&gt;
&lt;p&gt;&lt;figure&gt;
    &lt;img loading=&#34;lazy&#34; src=&#34;https://arunrocks.com/static/images/blog/blackholes-2.png&#34; alt=&#34;Obligatory XKCD 353&#34;  title=&#34;import gravity - Obligatory XKCD 353&#34;  width=518 height=&#34;588&#34;  /&gt;
    &lt;figcaption&gt;import gravity - Obligatory XKCD 353&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;Working with third party C libraries is not for the weak hearted. In 2002, when I was adapting the algorithm in a paper for my project on wavelet-based image compression, I learnt this the hard way. We needed to use an existing Fast Fourier transform library written in C.&lt;/p&gt;
&lt;div data-pullquote=&#34;Python code was pretty much a direct translation of the mathematics in the paper to code.&#34;&gt;
&lt;/div&gt;
&lt;p&gt;The library worked when you used it as is. But if you tried to extend a data structure, you might end up with a null pointer exception. Manual memory management by working out all the code paths turned out to be very stressful. The library was well documented but we practically needed to understand every line before tweaking it.&lt;/p&gt;
&lt;p&gt;Eventually, we gave up and started implementing most of the project in Python. It was much easier to work with higher level data structures like dictionaries and lists without going through the dance of malloc and free. Even better, the Python code was pretty much a direct translation of the mathematics in the paper to code.&lt;/p&gt;
&lt;p&gt;Python libraries tend to compose quite well (while &lt;a href=&#34;https://www.infoq.com/podcasts/rust-systems-programming&#34;&gt;C libraries don&amp;rsquo;t&lt;/a&gt;). This is partly due to its dynamic typing and automatic memory management, but I personally feel it is mainly due to good conventions. Most of the Python idioms are &lt;a href=&#34;https://www.python.org/dev/peps/pep-0020/&#34;&gt;well documented&lt;/a&gt; and this leads to minimum surprises. For instance, a deeply nested class hierarchy is frowned upon because &amp;ldquo;flat is better&amp;rdquo;.&lt;/p&gt;
&lt;h3 id=&#34;interactive-exploration&#34;&gt;Interactive Exploration&lt;/h3&gt;
&lt;p&gt;Research is explorative. We not know what we may find. Even if we do, we cannot wait for ages to find out because we might be chasing a dead end. An interactive interface is a key tool for a researcher or scientist. A Jupyter notebook is close to the ideal with its live code and embedded visualization abilities.&lt;/p&gt;
&lt;p&gt;If you need to try a computation with a different set of parameters, you can invoke it and view the results. Even plot it to visualize it better. Then you could take the results and feed it to another computation. This recorded transcript is a valuable data pipeline that can be replayed by a different user for verification or with a different set of observations.&lt;/p&gt;
&lt;p&gt;If you think about it, a conversational interface could be more approachable to a non-programmer. Alan Kay was very impressed with an &lt;a href=&#34;http://openvault.wgbh.org/catalog/V_D9DC82D997454711A71B586E17D23119&#34;&gt;early interactive programming environment called JOSS&lt;/a&gt; developed in RAND that appealed to economists. I find it endearing that &lt;a href=&#34;https://en.wikipedia.org/wiki/JOSS&#34;&gt;it replied to any command&lt;/a&gt; it did not understand with a &amp;ldquo;Eh?&amp;rdquo; or &amp;ldquo;SORRY&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;Imagine using today&amp;rsquo;s voice recognition technology to build such a conversational virtual assistant for scientists. Considering much of science (especially physics) involves mathematics &amp;ndash; spelling out complex equations can quickly get tedious. Listening to tables of numbers is no fun either. So unless the conversation steps up with an amazing level of artificial intelligence (imagine &lt;a href=&#34;https://marvelcinematicuniverse.fandom.com/wiki/J.A.R.V.I.S./Quote&#34;&gt;a reply&lt;/a&gt; like &amp;ldquo;I have run simulations on every known element, and none can serve as a viable replacement for the palladium core.&amp;quot;), we are probably stuck with current interfaces.&lt;/p&gt;
&lt;h3 id=&#34;future-of-python&#34;&gt;Future of Python&lt;/h3&gt;
&lt;p&gt;&lt;figure&gt;
    &lt;img loading=&#34;lazy&#34; src=&#34;https://arunrocks.com/static/images/blog/blackholes-3.png&#34; alt=&#34;Katie Bouman&#34;  title=&#34;Katie Bouman, one of the key contributors, with the amazing amount of data&#34;  width=720 height=&#34;406&#34;  /&gt;
    &lt;figcaption&gt;Katie Bouman, one of the key contributors, with the amazing amount of data&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;M87 EHT project involved processing petabytes of information (which is &lt;a href=&#34;http://vlbiimaging.csail.mit.edu/real&#34;&gt;publicly available&lt;/a&gt;). They plan to add new telescopes in the future, increasing the volume of data by orders of magnitude. In general, the computational demands of science will keep growing and even enter new domains. The question is - will Python keep up or get replaced?&lt;/p&gt;
&lt;p&gt;Python has a strong ecosystem with hundreds of libraries. It will be hard for another language to reproduce that. It is a very easy language to pick up. The readability is so good that Python code is often compared to pseudocode. I believe, it has changed the expectation of how code should look like. Any new language should have equal or better readability to inspire a switch.&lt;/p&gt;
&lt;p&gt;While there are several other promising languages like Julia or Rust, I am confident that Python will remain the scientist&amp;rsquo;s favourite programming language for a long while. Despite its limitations, Python has found a sweet spot between ease and power.&lt;/p&gt;
&lt;p&gt;Every year technological progresses keeps accelerating. This can translate into progress for humanity if we can make technology more accessible. We need physicists, mathematicians, biologists, economists, farmers and so on to use cheap computing power to build better things.&lt;/p&gt;
&lt;p&gt;Python does play a significant role by making coding less intimidating and more collaborative. That&amp;rsquo;s why I believe you will see it in bringing more people to computers and being a part of more future breakthroughs.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Understanding Django Channels</title>
      <link>https://arunrocks.com/understanding-django-channels/</link>
      <pubDate>Tue, 03 Jul 2018 06:55:30 +0530</pubDate>
      
      <guid>https://arunrocks.com/understanding-django-channels/</guid>
      <description>&lt;div class=&#34;series-box&#34;&gt;
&lt;p&gt;You are reading a post from a two-part tutorial series on Django Channels&lt;/p&gt;
&lt;ul&gt;
    &lt;li&gt;&lt;a href=&#34;https://arunrocks.com/get-started-with-async-and-await/&#34;&gt;Part 1&lt;/a&gt;&lt;/li&gt;
    &lt;li class=&#34;active&#34;&gt;&lt;a href=&#34;https://arunrocks.com/understanding-django-channels/&#34;&gt;Part 2&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;h2 id=&#34;django-channels&#34;&gt;Django Channels&lt;/h2&gt;
&lt;p&gt;Django Channels was originally created to solve the problem of handling asynchronous communication protocols like say WebSockets. More and more web applications were providing realtime capabilities like chat and push notifications. Various workarounds were created to make Django support such requirements like running separate socket servers or proxy servers.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://channels.readthedocs.io/en/latest/&#34;&gt;Channels&lt;/a&gt; is an official Django project not just for handling WebSockets and other forms of bi-directional communication but also for running background tasks asynchronously. As of writing, Django Channels 2 is out which is a complete rewrite based on Python 3&amp;rsquo;s async/await based coroutines.&lt;/p&gt;
&lt;p&gt;This article covers the concepts of Django Channels and leads you to a video tutorial implementing a notifications application in Django.&lt;/p&gt;
&lt;p&gt;Here is a simplified block diagram of a typical Channels setup:&lt;/p&gt;
&lt;p&gt;&lt;figure&gt;
    &lt;img loading=&#34;lazy&#34; src=&#34;https://arunrocks.com/static/images/blog/django-channels.png&#34; alt=&#34;Django Channels&#34;   width=1634 height=&#34;834&#34;  /&gt;
    
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;How a typical Django Channels infrastructure works&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;A client such as a web browser sends both HTTP/HTTPS and WebSocket traffic to an ASGI server like Daphene. Like WSGI, the ASGI (Asynchronous Server Gateway Interface) specification is a common way for applications servers and applications to interact with each other asynchronously.&lt;/p&gt;
&lt;p&gt;Like a typical Django application, HTTP traffic is handled synchronously i.e. when the browser sends a request, it waits until it is routed to Django and a response is sent back. However, it gets a lot more interesting when WebSocket traffic happens because it can be triggered from either direction.&lt;/p&gt;
&lt;div data-pullquote=&#34;&amp;#34;Ironically, you can write Channel applications without using Channels!&amp;#34;&#34;&gt;
&lt;/div&gt;
&lt;p&gt;Once a WebSocket connection is established, a browser can send or receive messages. A sent message reaches the Protocol type router that determines the next routing handler based on its transport protocol. Hence you can define a router for HTTP and another for WebSocket messages.&lt;/p&gt;
&lt;p&gt;These routers are very similar to Django&amp;rsquo;s URL mappers but map the incoming messages to a consumer (rather than a view). A &lt;strong&gt;consumer&lt;/strong&gt; is like an event handler that reacts to events. It can also send messages back to the browser, thereby containing the logic for a fully bi-directional communication.&lt;/p&gt;
&lt;p&gt;A consumer is a class whose methods you may choose to write either as normal Python functions (synchronous) or as awaitables (asynchronous). Asynchronous code should not mix with synchronous code. So there are conversion functions to convert from async to sync and back. Remember that the Django parts are synchronous. A consumer in fact a valid ASGI application.&lt;/p&gt;
&lt;p&gt;So far, we have not used the channel layer. Ironically, you can write Channel applications without using Channels! But they are not particularly useful as there is no easy communication path between application instances, other than polling a database. Channels provides exactly that, a fast point-to-point and broadcast messaging between application instances.&lt;/p&gt;
&lt;p&gt;A &lt;strong&gt;channel&lt;/strong&gt; is like a pipe. A sender sends a message to this pipe from one end and it reaches a listener at the other end. A &lt;strong&gt;group&lt;/strong&gt; defines a group of channels who are all listening to a topic. Every consumer listens to own auto-generated channel accessed by its &lt;code&gt;self.channel_name&lt;/code&gt; attribute.&lt;/p&gt;
&lt;p&gt;In addition to transports, you can trigger a consumer listening to a channel by sending a message, thereby starting a background task. This works as a very quick and simple background worker system.&lt;/p&gt;
&lt;h2 id=&#34;building-a-channels-application-step-by-step&#34;&gt;Building a Channels Application Step-by-step&lt;/h2&gt;
&lt;p&gt;The following screencast covers the creation of a notification application using Django Channels. You can access the &lt;a href=&#34;https://github.com/arocks/channels-example/&#34;&gt;code on Github&lt;/a&gt;. The intermediate projects like the Echo Consumer can be accessed as branches of the git repository.&lt;/p&gt;

&lt;div style=&#34;position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;&#34;&gt;
  &lt;iframe src=&#34;https://www.youtube.com/embed/G_EM5WM_08Q&#34; style=&#34;position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;&#34; allowfullscreen title=&#34;YouTube Video&#34;&gt;&lt;/iframe&gt;
&lt;/div&gt;

&lt;p&gt;The &lt;a href=&#34;https://github.com/arocks/channels-example/blob/master/show-notes.md&#34;&gt;show notes can be accessed on Github&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Check out the video tutorial and let me know if you found it useful! To know more, read the &lt;a href=&#34;https://channels.readthedocs.io/en/latest/&#34;&gt;Django Channels documentation&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&#34;series-box&#34;&gt;
&lt;p&gt;This article contains an excerpt from &lt;a href=&#34;https://arunrocks.com/static/book/django-design-patterns-best-practices-2-ed/&#34;&gt;&#34;Django Design Patterns and Best Practices&#34;&lt;/a&gt; by Arun Ravindran&lt;/p&gt;
&lt;/div&gt;
</description>
    </item>
    
    <item>
      <title>Get started with Async &amp; Await</title>
      <link>https://arunrocks.com/get-started-with-async-and-await/</link>
      <pubDate>Wed, 14 Mar 2018 06:55:30 +0530</pubDate>
      
      <guid>https://arunrocks.com/get-started-with-async-and-await/</guid>
      <description>&lt;div class=&#34;series-box&#34;&gt;
&lt;p&gt;You are reading a post from a two-part tutorial series on Django Channels&lt;/p&gt;
&lt;ul&gt;
    &lt;li class=&#34;active&#34;&gt;&lt;a href=&#34;https://arunrocks.com/get-started-with-async-and-await/&#34;&gt;Part 1&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href=&#34;https://arunrocks.com/understanding-django-channels/&#34;&gt;Part 2&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;h2 id=&#34;asyncio&#34;&gt;Asyncio&lt;/h2&gt;
&lt;p&gt;&lt;a href=&#34;https://docs.python.org/3/library/asyncio.html&#34;&gt;Asyncio&lt;/a&gt; is a co-operative multitasking library available in Python since version 3.6. &lt;a href=&#34;http://www.celeryproject.org/&#34;&gt;Celery&lt;/a&gt; is fantastic for running concurrent tasks out of process, but there are certain times you would need to run multiple tasks in a single thread inside a single process.&lt;/p&gt;
&lt;p&gt;If you are not familiar with async/await concepts (say from JavaScript or C#) then it involves a bit of steep learning curve. However, it is well worth your time as it can speed up your code tremendously (unless it is completely CPU-bound). Moreover, it helps in understanding other libraries built on top of them like Django Channels.&lt;/p&gt;
&lt;p&gt;This post is an attempt to explain the concepts in a simplified manner rather than try to be comprehensive. I want you to start using asynchronous programming and enjoy it. You can learn the nitty gritties later.&lt;/p&gt;
&lt;div data-pullquote=&#34;&amp;#34;Unlike a normal function call, if you invoke a coroutine its body will not get executed right away&amp;#34;&#34;&gt;
&lt;/div&gt;
&lt;p&gt;All asyncio programs are driven by an &lt;strong&gt;event loop&lt;/strong&gt;, which is pretty much an indefinite loop that calls all registered coroutines in some order until they all terminate. Each coroutine operates cooperatively by yielding control to fellow coroutines at well-defined places. This is called awaiting.&lt;/p&gt;
&lt;p&gt;A &lt;strong&gt;coroutine&lt;/strong&gt; is like a special function which can suspend and resume execution. They work like lightweight threads. Native coroutines use the async and await keywords, as follows:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;asyncio&lt;/span&gt;


&lt;span class=&#34;n&#34;&gt;async&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;sleeper_coroutine&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;():&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;await&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;asyncio&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;sleep&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;5&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;


&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;vm&#34;&gt;__name__&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;__main__&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;loop&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;asyncio&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;get_event_loop&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;loop&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;run_until_complete&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;sleeper_coroutine&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This is a minimal example of an event loop running one coroutine named &lt;strong&gt;sleeper_coroutine&lt;/strong&gt;. When invoked this coroutine runs until the await statement and yields control back to the event loop. This is usually where an Input/Output activity occurs.&lt;/p&gt;
&lt;p&gt;The control comes back to the coroutine at the same line when the activity being awaited is completed (after five seconds). Then then coroutine returns or is considered completed.&lt;/p&gt;
&lt;h2 id=&#34;explain-async-and-await&#34;&gt;Explain async and await&lt;/h2&gt;
&lt;p&gt;[TLDR; &lt;a href=&#34;https://www.youtube.com/watch?v=wDESPxBOtvY&#34;&gt;Watch my screencast&lt;/a&gt; to understand this section with a lot more code examples.]&lt;/p&gt;
&lt;p&gt;Initially, I was confused by the presence of the new keywords in Python: &lt;strong&gt;async&lt;/strong&gt; and &lt;strong&gt;await&lt;/strong&gt;. Asynchronous code seemed to be littered with these keywords yet it was not clear what they did or when to use them.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s first look at the &lt;code&gt;async&lt;/code&gt; keyword. Commonly used before a function definition as &lt;code&gt;async def&lt;/code&gt;, it indicates that you are defining a (native) coroutine.&lt;/p&gt;
&lt;p&gt;You should know two things about coroutines:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Don&amp;rsquo;t perform slow or blocking operations synchronously inside coroutines.&lt;/li&gt;
&lt;li&gt;Don&amp;rsquo;t call a coroutine directly like a regular function call. Either schedule it in an event loop or await it from another coroutine.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Unlike a normal function call, if you invoke a coroutine its body will not get executed right away. Instead it will be suspended and returns a coroutine object. Invoking the send method of this coroutine will start the execution of the coroutine body.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;async&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;hi&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;():&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;...&lt;/span&gt;     &lt;span class=&#34;k&#34;&gt;print&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;HOWDY!&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;...&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;o&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;hi&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;o&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;coroutine&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;object&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;hi&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;at&lt;/span&gt; &lt;span class=&#34;mh&#34;&gt;0x000001DAE26E2F68&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;o&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;send&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;bp&#34;&gt;None&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;HOWDY&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;!&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;Traceback&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;most&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;recent&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;call&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;last&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;
  &lt;span class=&#34;n&#34;&gt;File&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;lt;stdin&amp;gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;line&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;module&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&#34;ne&#34;&gt;StopIteration&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;However, when the coroutine returns it will end in a StopIteration exception. Hence it is better to use the asyncio provided event loop to run a coroutine. The loop will handle exceptions in addition to all other machinery for running coroutines concurrently.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;asyncio&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;loop&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;asyncio&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;get_event_loop&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;o&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;hi&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;loop&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;run_until_complete&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;o&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;HOWDY&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;!&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Next we have the &lt;code&gt;await&lt;/code&gt; keyword which must be only used inside a coroutine. If you call another coroutine, chances are that it might get blocked at some point, say while waiting for I/O.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;async&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;sleepy&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;():&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;...&lt;/span&gt;     &lt;span class=&#34;n&#34;&gt;await&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;asyncio&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;sleep&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;...&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;o&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sleepy&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;loop&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;run_until_complete&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;o&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# After three seconds&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;a href=&#34;https://docs.python.org/3/library/asyncio-task.html#asyncio.sleep&#34;&gt;sleep&lt;/a&gt; coroutine from asyncio module is different from its synchronous counterpart &lt;a href=&#34;https://docs.python.org/3/library/time.html#time.sleep&#34;&gt;time.sleep&lt;/a&gt;. It is non-blocking. This means that other coroutines can be executed while this coroutine is awaiting the sleep to be completed.&lt;/p&gt;
&lt;p&gt;When a coroutine uses the await keyword to call another coroutines, it acts like a bookmark. When a blocking operation happens, it suspends the coroutine (and all the coroutines who are await-ing it) and returns control back to the event loop. Later, when the event loop is notified of the completion of the blocking operation, then the execution is resumed from the await expression paused and continues onward.&lt;/p&gt;
&lt;h2 id=&#34;asyncio-vs-threads&#34;&gt;Asyncio vs Threads&lt;/h2&gt;
&lt;p&gt;If you have worked on multi-threaded code, then you might wonder – Why not just use threads? There are several reasons why threads are not popular in Python.&lt;/p&gt;
&lt;div data-pullquote=&#34;&amp;#34;If you can run a maximum of hundreds of threads, then you might be able to run tens of thousands of coroutines given the same memory&amp;#34;&#34;&gt;
&lt;/div&gt;
&lt;p&gt;Firstly, threads need to be synchronized while accessing shared resources or we will have race conditions. There are several types of synchronization primitives like locks but essentially, they involve waiting which degrades performance and could cause deadlocks or starvation.&lt;/p&gt;
&lt;p&gt;A thread may be interrupted any time. Coroutines have well-defined places where execution is handed over i.e. co-operative multitasking. As a result, you may make changes to a shared state as long as you leave it in a known state. For instance you can retrieve a field from a database, perform calculations and overwrite the field without worrying that another coroutine might have interrupted you in between. All this is possible without locks.&lt;/p&gt;
&lt;p&gt;Secondly, coroutines are lightweight. Each coroutine needs an order of magnitude less memory than a thread. If you can run a maximum of hundreds of threads, then you might be able to run tens of thousands of coroutines given the same memory. Thread switching also takes some time (few milliseconds). This means you might be able to run more tasks or serve more concurrent users (just like how Node.js works on a single thread without blocking).&lt;/p&gt;
&lt;p&gt;The downsides of coroutines is that you cannot mix blocking and non-blocking code. So once you enter the event loop, rest of the code driven by it must be written in asynchronous style, even the standard or third-party libraries you use. This might make using some older libraries with synchronous code somewhat difficult.&lt;/p&gt;
&lt;p&gt;If you really want to call asynchronous code from synchronous or vice versa, then do read this &lt;a href=&#34;https://www.aeracode.org/2018/02/19/python-async-simplified/&#34;&gt;excellent overview&lt;/a&gt; of various cases and adaptors you can use by Andrew Godwin.&lt;/p&gt;
&lt;h2 id=&#34;the-classic-web-scraper-example&#34;&gt;The Classic Web-scraper Example&lt;/h2&gt;
&lt;p&gt;Let&amp;rsquo;s look at an example of how we can rewrite synchronous code into asynchronous. We will look at a webscraper which downloads pages from a couple of URLs and measures its size. This is a common example because it is very I/O bound which shows a significant speedup when handled concurrently.&lt;/p&gt;
&lt;h3 id=&#34;synchronous-web-scraping&#34;&gt;Synchronous web scraping&lt;/h3&gt;
&lt;p&gt;The synchronous scraper uses Python 3 standard libraries like urllib. It downloads the home page of three popular sites and the fourth is a large file to simulate a slow connection. It prints the respective page sizes and the total running time.&lt;/p&gt;
&lt;p&gt;Here is the code for the synchronous scraper:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# sync.py&lt;/span&gt;
&lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&amp;#34;Synchronously download a list of webpages and time it&amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;span class=&#34;kn&#34;&gt;from&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;urllib.request&lt;/span&gt; &lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Request&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;urlopen&lt;/span&gt;
&lt;span class=&#34;kn&#34;&gt;from&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;time&lt;/span&gt; &lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;time&lt;/span&gt;

&lt;span class=&#34;n&#34;&gt;sites&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;
    &lt;span class=&#34;s2&#34;&gt;&amp;#34;https://news.ycombinator.com/&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
    &lt;span class=&#34;s2&#34;&gt;&amp;#34;https://www.yahoo.com/&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
    &lt;span class=&#34;s2&#34;&gt;&amp;#34;https://github.com/&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;


&lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;find_size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;url&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;req&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Request&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;url&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
    &lt;span class=&#34;k&#34;&gt;with&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;urlopen&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;req&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;as&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;response&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
        &lt;span class=&#34;n&#34;&gt;page&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;response&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;read&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
        &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;len&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;page&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;


&lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;():&lt;/span&gt;
    &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;site&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sites&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
        &lt;span class=&#34;n&#34;&gt;size&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;find_size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;site&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
        &lt;span class=&#34;k&#34;&gt;print&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;Read {:8d} chars from {}&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;format&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;site&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;


&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;vm&#34;&gt;__name__&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;__main__&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;start_time&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;time&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
    &lt;span class=&#34;k&#34;&gt;print&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;Ran in {:6.3f} secs&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;format&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;time&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;start_time&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;On a test laptop, this code took 5.4 seconds to run. It is the cumulative loading time of each site. Let&amp;rsquo;s see how asynchronous code runs.&lt;/p&gt;
&lt;h3 id=&#34;asynchronous-web-scraping&#34;&gt;Asynchronous web scraping&lt;/h3&gt;
&lt;p&gt;This asyncio code requires installation of a few Python asynchronous network libraries such as aiohttp and aiodns. They are mentioned in the docstring.&lt;/p&gt;
&lt;p&gt;Here is the code for the asynchronous scraper – it is structured to be as close as possible to the synchronous version so it is easier to compare:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# async.py&lt;/span&gt;
&lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&amp;#34;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;Asynchronously download a list of webpages and time it
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;Dependencies: Make sure you install aiohttp using: pip install aiohttp aiodns
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;asyncio&lt;/span&gt;
&lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;aiohttp&lt;/span&gt;
&lt;span class=&#34;kn&#34;&gt;from&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;time&lt;/span&gt; &lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;time&lt;/span&gt;

&lt;span class=&#34;c1&#34;&gt;# Configuring logging to show timestamps&lt;/span&gt;
&lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;logging&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;logging&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;basicConfig&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;format&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;%(asctime)s&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt; &lt;/span&gt;&lt;span class=&#34;si&#34;&gt;%(message)s&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;datefmt&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;[%H:%M:%S]&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;log&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;logging&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;getLogger&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;log&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;setLevel&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;logging&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;INFO&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;

&lt;span class=&#34;n&#34;&gt;sites&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;
    &lt;span class=&#34;s2&#34;&gt;&amp;#34;https://news.ycombinator.com/&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
    &lt;span class=&#34;s2&#34;&gt;&amp;#34;https://www.yahoo.com/&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
    &lt;span class=&#34;s2&#34;&gt;&amp;#34;https://github.com/&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;


&lt;span class=&#34;n&#34;&gt;async&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;find_size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;session&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;url&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;log&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;info&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;START {}&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;format&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;url&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;async&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;with&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;session&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;get&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;url&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;as&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;response&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
        &lt;span class=&#34;n&#34;&gt;log&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;info&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;RESPONSE {}&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;format&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;url&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;
        &lt;span class=&#34;n&#34;&gt;page&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;await&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;response&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;read&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
        &lt;span class=&#34;n&#34;&gt;log&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;info&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;PAGE {}&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;format&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;url&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;
        &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;url&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;len&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;page&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;


&lt;span class=&#34;n&#34;&gt;async&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;():&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;tasks&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[]&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;async&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;with&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;aiohttp&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ClientSession&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;as&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;session&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
        &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;site&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sites&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
            &lt;span class=&#34;n&#34;&gt;tasks&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;append&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;find_size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;session&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;site&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;
        &lt;span class=&#34;n&#34;&gt;results&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;await&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;asyncio&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;gather&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;tasks&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
    &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;site&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;size&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;results&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
        &lt;span class=&#34;k&#34;&gt;print&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;Read {:8d} chars from {}&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;format&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;site&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;


&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;vm&#34;&gt;__name__&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;__main__&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;start_time&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;time&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;loop&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;asyncio&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;get_event_loop&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;loop&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;set_debug&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;bp&#34;&gt;True&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;loop&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;run_until_complete&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;())&lt;/span&gt;
    &lt;span class=&#34;k&#34;&gt;print&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;Ran in {:6.3f} secs&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;format&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;time&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;start_time&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The main function is a coroutine which triggers the creation of a separate coroutine for each website. Then it awaits until all these triggered coroutines are completed. As a best practice, the web session object is passed to avoid re-creating new sessions for each page.&lt;/p&gt;
&lt;p&gt;The total running time of this program on the same test laptop is 1.5 s. This is a speedup of 3.6x on the same single core. This surprising result can be better understood if we can visualize how the time was spent, as shown below:&lt;/p&gt;
&lt;p&gt;&lt;figure&gt;
    &lt;img loading=&#34;lazy&#34; src=&#34;https://arunrocks.com/static/images/blog/async-await.png&#34; alt=&#34;Comparing scrapers&#34;   width=1703 height=&#34;920&#34;  /&gt;
    
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;A simplistic representation comparing tasks in the synchronous and asynchronous scrapers&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The synchronous scraper is easy to understand. Scraping activity needs very little CPU time and the majority of the time is spent waiting for the data to arrive from the network. Each task is waiting for the previous task to complete. As a result the tasks cascade sequentially like a waterfall.&lt;/p&gt;
&lt;p&gt;On the other hand the asynchronous scraper starts the first task and as soon as it starts waiting for I/O, it switches to the next task. The CPU is hardly idle as the execution goes back to the event loop as soon as the waiting starts. Eventually the I/O completes in the same amount of time but due to the multiplexing of activity, the overall time taken is drastically reduced.&lt;/p&gt;
&lt;p&gt;In fact, the asynchronous code can be speeded up further. The standard asyncio event loop is written in pure Python and provided as a reference implementation. You can consider faster implementations like &lt;a href=&#34;https://github.com/MagicStack/uvloop&#34;&gt;uvloop&lt;/a&gt; for further speedup (my running time came down to 1.3 secs).&lt;/p&gt;
&lt;h2 id=&#34;concurrency-is-not-parallelism&#34;&gt;Concurrency is not Parallelism&lt;/h2&gt;
&lt;p&gt;Concurrency is the ability to perform other tasks while you are waiting on the current task. Imagine you are cooking a lot of dishes for some guests. While waiting for something to cook, you are free to do other things like peeling onions or cutting vegetables. Even when one person cooks, typically there will be several things happening &lt;em&gt;concurrently&lt;/em&gt;.&lt;/p&gt;
&lt;div data-pullquote=&#34;&amp;#34;Optimal usage of your computing resources require both concurrency and parallelism&amp;#34;&#34;&gt;
&lt;/div&gt;
&lt;p&gt;Parallelism is when two or more execution engines are performing a task. Continuing on our analogy, this is when two or more cooks work on the same dish to (hopefully) save time.&lt;/p&gt;
&lt;p&gt;It is very easy to confuse concurrency and parallelism because they can happen at the same time. You could be concurrently running tasks without parallelism or vice versa. But they refer to two different things. Concurrency is a way of structuring your programs while Parallelism refers to how it is executed.&lt;/p&gt;
&lt;p&gt;Due to the Global Interpreter Lock, we cannot run more than one thread of the Python interpreter (to be specific, the standard CPython interpreter) at a time even in multicore systems. This limits the amount of parallelism which we can achieve with a single instance of the Python process.&lt;/p&gt;
&lt;p&gt;Optimal usage of your computing resources require both concurrency and parallelism. Concurrency will help you avoid idling the processor core while waiting for say I/O events. While parallelism will help distribute work among all the available cores.&lt;/p&gt;
&lt;p&gt;In both cases, you are not executing synchronously i.e. waiting for a task to finish before moving on to another task. Asynchronous systems might seem to be the most optimal. However, they are harder to build and reason about.&lt;/p&gt;
&lt;h2 id=&#34;why-another-asynchronous-framework&#34;&gt;Why another Asynchronous Framework?&lt;/h2&gt;
&lt;p&gt;Asyncio is by no means the first cooperative multitasking or light-weight thread library. If you have used gevent or eventlet, you might find asyncio needs more explicit separation between synchronous and asynchronous code. This is usually a good thing.&lt;/p&gt;
&lt;p&gt;Gevent, relies on monkey-patching to change blocking I/O calls to non-blocking ones. This can lead to hard to find performance issues due to an unpatched blocking call slowing the event loop. As the Zen says, &amp;lsquo;Explicit is better than Implicit&amp;rsquo;.&lt;/p&gt;
&lt;p&gt;Another objective of asyncio was to provide a standardized concurrency framework for all implementations like gevent or Twisted. This not only reduces duplicated efforts by library authors but also ensures that code is portable for end users.&lt;/p&gt;
&lt;p&gt;Personally, I think the asyncio module can be more streamlined. There are a lot of ideas which somewhat expose implementation details (e.g. native coroutines vs generator-based coroutines). But it is useful as a standard to write future-proof code.&lt;/p&gt;
&lt;h2 id=&#34;can-we-use-asyncio-in-django&#34;&gt;Can we use asyncio in Django?&lt;/h2&gt;
&lt;p&gt;Strictly speaking, the answer is No. Django is a synchronous web framework. You might be able to run a seperate worker process, say in Celery, to run an embedded event loop. This can be used for I/O background tasks like web scraping.&lt;/p&gt;
&lt;p&gt;However, &lt;a href=&#34;https://channels.readthedocs.io/en/latest/&#34;&gt;Django Channels&lt;/a&gt; changes all that. Django might fit in the asynchronous world after all. But that&amp;rsquo;s the subject of another post.&lt;/p&gt;
&lt;div class=&#34;series-box&#34;&gt;
&lt;p&gt;This article contains an excerpt from &lt;a href=&#34;https://arunrocks.com/static/book/django-design-patterns-best-practices-2-ed/&#34;&gt;&#34;Django Design Patterns and Best Practices&#34;&lt;/a&gt; by Arun Ravindran&lt;/p&gt;
&lt;/div&gt;
</description>
    </item>
    
    <item>
      <title>Interview with Daniel Roy Greenfeld (PyDanny)</title>
      <link>https://arunrocks.com/interview-with-daniel-roy-greenfeld-pydanny/</link>
      <pubDate>Fri, 09 Feb 2018 15:15:11 +0530</pubDate>
      
      <guid>https://arunrocks.com/interview-with-daniel-roy-greenfeld-pydanny/</guid>
      <description>&lt;p&gt;Daniel Roy Greenfeld needs no introduction to Djangonauts. Co-author of the book &lt;a href=&#34;https://www.twoscoopspress.com/products/two-scoops-of-django-1-8&#34;&gt;Two Scoops of Django&lt;/a&gt; which is probably on the shelves of any serious Django practitioner. But PyDanny, as he is fondly known as, is also a wonderful fiction author, fitness enthusiast and a lot more.&lt;/p&gt;
&lt;p&gt;Having known Daniel for a while as a wonderful friend and a great inspiration, I am so excited that he agreed to my interview. Let&amp;rsquo;s get started&amp;hellip;&lt;/p&gt;
&lt;p&gt;&lt;figure&gt;
    &lt;img loading=&#34;lazy&#34; src=&#34;https://arunrocks.com/static/images/blog/pydanny.jpg&#34; alt=&#34;PyDanny Photo&#34;   width=500 height=&#34;753&#34;  /&gt;
    
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;How did the idea of writing an ice-cream themed book occur?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The first 50 pages that I wrote were angry and were for a book with an angry name. You see, I was tired of having to pick up after sloppy or unwise coding practices on rescue projects. I was furious and wanted to fix the world.&lt;/p&gt;
&lt;p&gt;However, I was getting stuck in what I wanted to say, or didn&amp;rsquo;t know things. I kept asking my normal favorite resource for help, Audrey Roy Greenfeld. Eventually she started to write (or rewrite) whole sections and I realized that I wasn&amp;rsquo;t writing the book alone.&lt;/p&gt;
&lt;p&gt;Therefore I asked Audrey to be my co-author. She&amp;rsquo;s a cheerful person and said that if she were to accept, the book had to be lightened. That meant changing the name. After a lot of different title names discussed over many ice cream sessions, we decided to use the subject matter at hand. Which worked out well as the ice cream theme made for a good example subject.&lt;/p&gt;
&lt;div data-pullquote=&#34;&amp;#34;Neither of us are big believers in multi-tasking, so sticking to one thing is important to us.&amp;#34;&#34;&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;How do you and Audrey collaborate while writing a book?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;We take turns writing original material that interests us. The other person follows them and acts as editor and proofreader. We go back and forth a few hundred times and there you go.&lt;/p&gt;
&lt;p&gt;For tech writing we use Git as version control and LaTeX for formatting. For fiction we use Google docs followed by some Python scripts that merge and format the files.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What&amp;rsquo;s the most exciting recent development in Django? Where do you think it can improve?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I like the new URL system as it&amp;rsquo;s really nice for beginners and advanced coders alike. While I like writing regular expressions, I&amp;rsquo;m the exception in this case.&lt;/p&gt;
&lt;p&gt;Where I think where Django can improve is having more non-US/Europe/Australian representation within the DSF and in the core membership. In short, most of Django core looks like me, and I think that&amp;rsquo;s wrong. Many of the best Django (and Python) people look nothing like me, and they deserve more recognition. While having Anna Makarudze on the DSF board is a wonderful development, as a community we can still do better in core.&lt;/p&gt;
&lt;p&gt;In the case of Django&amp;rsquo;s core team, I believe this has happened because all the major Django conferences are in the US, Europe, and Australia, and from what I&amp;rsquo;ve seen over the years it&amp;rsquo;s through participation in those events is how most people get onto the Django core team. The DSF is aware of the problem, but I think more people should raise it as an issue. More people vocalizing this as a problem will get it resolved more quickly.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;With the Ambria fantasy series, you have proven to be a prolific fiction author too. Reminds me Lewis Carroll who wrote children&amp;rsquo;s books and mathematical treatises. What is the difference in the writing process while writing fiction and non-fiction?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;For us, the process is very similar. We both write and we both review our stuff. The difference is that if we make a mistake in our fiction, it&amp;rsquo;s not as critical. That means that the review process for fiction is a lot easier on us then it is to write technical books or articles. I can&amp;rsquo;t begin to tell you what a load that is off my shoulders.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Why fantasy? Any literary influences?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;We like fantasy because we can just let our imaginations run away with us. For the Ambria series, our influences include Tolkien, Joseph Campbell, Glen Cook, Greek mythology, and various equine and religious studies.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Do you have a daily writing routine?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Like coding on a fun project, when we get to write, we get up early and just start working. When we get hungry or thirsty we stop. The day seems to fly by and we are very happy. We try not to mix writing days with coding days, as we like to focus on one thing at a time. Neither of us are big believers in multi-tasking, so sticking to one thing is important to us.&lt;/p&gt;
&lt;div data-pullquote=&#34;&amp;#34;It&amp;#39;s our responsibility to the future to be aware that the tools we are playing with have a lot of power&amp;#34;&#34;&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;What&amp;rsquo;s your favorite part of the writing process?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Getting to write with my favorite person in the whole world, Audrey Roy Greenfeld. :-)&lt;/p&gt;
&lt;p&gt;Also, having people read our stuff and comment on it, both positively and negatively.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Do you ever get writer&amp;rsquo;s block?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Not usually. Our delays are almost always because of other things getting in the way. We&amp;rsquo;re very fortunate that way!&lt;/p&gt;
&lt;p&gt;When I do get writers block, I try to do something active. Be it exercise or fix something in the house that needs it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Considering you can do cartwheels, I am assuming you are pretty fit. Do you think technology folks don&amp;rsquo;t give it enough importance?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m older than I look but even dealing with an unpleasant knee injury move faster and better than 90% of software developers. And when I look at other coders my age, I see people old before their years. I believe youth is fleeting unless you take a little bit of time every day to keep your strength and flexibility.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Anything else you would like to say?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;To paraphrase Jurassic Park, &amp;ldquo;Just because you can do a thing doesn&amp;rsquo;t mean you should do a thing.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;As software developers, we have skills that let us do amazing things. With enough time and experience, we can do pretty much anything we are asked to do. That said, we should consider whether or not we should always do what we are asked to do.&lt;/p&gt;
&lt;p&gt;For example, the combined power of image recognition, big data, and distributed systems is really fun to play with, but we need to be aware that these tools can be dangerous. In the past year we&amp;rsquo;ve seen it used to affect opinion and elections, and this is only the beginning. It&amp;rsquo;s our responsibility to the future to be aware that the tools we are playing with have a lot of power, and that the people who are paying us to use them might not have the best intentions.&lt;/p&gt;
&lt;p&gt;Hence why I like to say, &amp;ldquo;Just because you can do a thing doesn&amp;rsquo;t mean you should do a thing.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Do checkout &lt;a href=&#34;https://www.twoscoopspress.com/products/two-scoops-of-django-1-8&#34;&gt;&amp;ldquo;Two Scoops of Django 1.11: Best Practices for the Django Web Framework&amp;rdquo;&lt;/a&gt; by Two Scoops Press&lt;/strong&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Django Release Schedule and Python 3</title>
      <link>https://arunrocks.com/django-release-schedule-and-python-3/</link>
      <pubDate>Tue, 30 Jan 2018 06:59:49 +0530</pubDate>
      
      <guid>https://arunrocks.com/django-release-schedule-and-python-3/</guid>
      <description>&lt;p&gt;Do long term releases confuse you? For the longest time I was not sure which version of Ubuntu to download - the latest release or the LTS? I see a number of Django developers confused about Django&amp;rsquo;s releases. So I prepared this handy guide to help you choose (or confuse?).&lt;/p&gt;
&lt;h2 id=&#34;which-version-to-use&#34;&gt;Which Version To Use?&lt;/h2&gt;
&lt;p&gt;Django has now &lt;a href=&#34;https://www.djangoproject.com/weblog/2015/jun/25/roadmap/&#34;&gt;standardized on a release schedule&lt;/a&gt; with three kinds of releases:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Feature Release&lt;/strong&gt;: These releases will have new features or improvements to existing features. It will happen every 8 months and will have 16 months of extended support from release. They have version numbers like A.B (note there&amp;rsquo;s no minor version).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Long-Term Support (LTS) Release&lt;/strong&gt;: These are special kind of feature releases, which have a longer extended support of three years from the release date. These releases will happen every two years. They have version numbers like A.2 (since every third feature release will be a LTS). LTS releases have few months of overlap to aid in a smoother migration.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Patch Release&lt;/strong&gt;: These releases are bug fixes or security patches. It is recommended to deploy them as soon as possible. Since they have minimal breaking changes, these upgrades should be painless to apply. They have version numbers like A.B.C&lt;/p&gt;
&lt;p&gt;Django roadmap visualized below should make the release approach clearer:&lt;/p&gt;
&lt;p&gt;&lt;figure&gt;
    &lt;img loading=&#34;lazy&#34; src=&#34;https://arunrocks.com/static/images/blog/django-releases.png&#34; alt=&#34;Django Releases (LTS and feature releases) explained&#34;   width=1741 height=&#34;1240&#34;  /&gt;
    
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;The dates are indicative and may change. This is not an official diagram but something that I created for my understanding.&lt;/p&gt;
&lt;p&gt;The big takeaway is that Django 1.11 LTS will be the last release to support Python 2 and it is supported until April 2020. Subsequent versions will use only Python 3.&lt;/p&gt;
&lt;p&gt;The right Django version for you will be based on how frequent you can upgrade your Django installation and what features you need. If your project is actively developed and the Django version can be upgraded at least once in 16 months, then you should install the latest feature release regardless of whether it is LTS or non-LTS.&lt;/p&gt;
&lt;p&gt;Otherwise, if your project is only occasionally developed then you should pick the most recent LTS version. Upgrading your project&amp;rsquo;s Django dependency from one feature release to another can be a non-trivial effort. So, read the release notes and plan accordingly.&lt;/p&gt;
&lt;p&gt;In any case, make sure you install Patch Releases as soon as they are released. Now, if you are still on Python 2 then read on.&lt;/p&gt;
&lt;h2 id=&#34;python-3-has-crossed-tipping-point&#34;&gt;Python 3 has crossed tipping point&lt;/h2&gt;
&lt;p&gt;When I decided to use Python 3 only while writing my book &amp;ldquo;Django Design Patterns and Best Practices&amp;rdquo; in 2015, it was a time when Python 2 versus Python 3 was hotly debated. However, to me Python 3 seemed much more cleaner without arcane syntax like class methods named &lt;code&gt;__unicode__&lt;/code&gt;  and classes needing to derive from &lt;code&gt;object&lt;/code&gt; parent class.&lt;/p&gt;
&lt;p&gt;Now, it is quite a different picture. We just saw how Django no longer supports Python 2 except for the last LTS release. This is a big push for many Python shops to consider Python 3.&lt;/p&gt;
&lt;p&gt;Many platforms have upgraded their default Python interpreter. Starting 1st March 2018, Python 3 is announced to be the default &amp;ldquo;python&amp;rdquo; in Homebrew installs. ArchLinux had completely switched to Python 3 since 2010.&lt;/p&gt;
&lt;p&gt;Fedora has switched to Python 3 as its system default since &lt;a href=&#34;https://fedoraproject.org/wiki/Changes/Python_3_as_Default&#34;&gt;version 23&lt;/a&gt;. Even though &lt;code&gt;python&lt;/code&gt; command will launch &lt;code&gt;python3&lt;/code&gt;, the symlink &lt;code&gt;/usr/bin/python&lt;/code&gt; will still point to &lt;code&gt;python2&lt;/code&gt; for backward compatibility. So it is probably a good idea to use &lt;code&gt;#!/usr/bin/env python&lt;/code&gt; idiom in your shell scripts.&lt;/p&gt;
&lt;p&gt;On 26 April 2018, when Ubuntu 18.04 LTS (Bionic Beaver) will be released, it is planned to be have &lt;a href=&#34;https://wiki.ubuntu.com/Python/Python36Transition&#34;&gt;Python 3.6 as default&lt;/a&gt;. Further upstream, the next Debian release in testing - Debian 10 (Buster) &lt;a href=&#34;https://wiki.ubuntu.com/Python/Python36Transition&#34;&gt;is expected to transition to Python 3.6&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Moving to packages, the &lt;a href=&#34;https://python3wos.appspot.com/&#34;&gt;Python 3 Wall of Superpowers&lt;/a&gt; shows that with the backing of 190 out of 200 packages, at the time of writing, we have nearly all popular Python packages on Python 3. The only notable package remaining is supervisor, which is about to turn green in &lt;a href=&#34;https://github.com/Supervisor/supervisor/blob/master/README.rst&#34;&gt;supervisor 4.0 (unreleased)&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&#34;common-python-3-migration-blockers&#34;&gt;Common Python 3 Migration Blockers&lt;/h3&gt;
&lt;p&gt;You might be aware of atleast one project which is still on Python 2. It could be open source or an internal project, which may be stuck in Python 3 for a number of reasons. I&amp;rsquo;ve come across a number of such projects and here is my response to such reasons:&lt;/p&gt;
&lt;h4 id=&#34;reason-1-my-project-is-too-complex&#34;&gt;Reason 1: My Project is too complex&lt;/h4&gt;
&lt;p&gt;Some very large and complex projects like NumPy or Django have been migrated sucessfully. You can learn the &lt;a href=&#34;https://docs.djangoproject.com/en/1.11/topics/python3/&#34;&gt;migration strategies of projects like Django&lt;/a&gt;. Django maintained a common codebase for Python 2 and 3 using the &lt;a href=&#34;https://pypi.python.org/pypi/six&#34;&gt;six&lt;/a&gt; (2 × 3=6, get it?) library before switching to Python 3 only.&lt;/p&gt;
&lt;h4 id=&#34;reason-2-i-still-have-time&#34;&gt;Reason 2: I still have time&lt;/h4&gt;
&lt;p&gt;It is closer than you think. &lt;a href=&#34;https://pythonclock.org/&#34;&gt;Python clock&lt;/a&gt; shows there is a little more than 2 years and 2 months left for Python 2 support.&lt;/p&gt;
&lt;p&gt;In fact, you have had a lot of time. It has been ten years since Python 3 was announced. That is a lot of overlap to transition from one version to another.&lt;/p&gt;
&lt;p&gt;In today&amp;rsquo;s &amp;lsquo;move fast and break things&amp;rsquo; world, a lot of projects decide to abruptly stop support and ask you to migrate as soon as a new release is out. This is a lot more realistic assumption for enterprises which need a lot more planning and testing.&lt;/p&gt;
&lt;h4 id=&#34;reason-3-i-have-to-learn-python-3&#34;&gt;Reason 3: I have to learn Python 3&lt;/h4&gt;
&lt;p&gt;But you already know most of it! You might need about 10 mins to learn the differences. In fact, I have written a post to guide &lt;a href=&#34;https://arunrocks.com/python-3-cheatsheet-for-djangonauts/&#34;&gt;Django coders to Python 3&lt;/a&gt;. Small Django/Python 2 projects need only trivial changes to work on Python 3.&lt;/p&gt;
&lt;p&gt;You might see many old blog posts about Python 3 being buggy or slow. Well, that has not been true for a while. Not only it is extremely stable and bug-free, it is actually used in production by several companies. Performance-wise it has been getting faster in every release, so it is faster than Python 2 in most cases and slower in a few.&lt;/p&gt;
&lt;p&gt;Of course, there are lot of awesome new features and libraries added to Python 3. You can learn them as and when you need them. I would recommend reading the release notes to understand them. I will mention my favourites soon.&lt;/p&gt;
&lt;h4 id=&#34;reason-4-nobody-is-asking&#34;&gt;Reason 4: Nobody is asking&lt;/h4&gt;
&lt;p&gt;Some people have the philosophy that if nobody is asking then nobody cares. Well, they do care if the application they run is on an unsupported technology. Better plan for the eventual transition than rush it on a higher budget.&lt;/p&gt;
&lt;h2 id=&#34;are-you-missing-out&#34;&gt;Are you missing out?&lt;/h2&gt;
&lt;p&gt;&lt;figure&gt;
    &lt;img loading=&#34;lazy&#34; src=&#34;https://arunrocks.com/static/images/blog/box-of-chocs.jpg&#34; alt=&#34;Image by https://pixabay.com/en/users/GlenisAymara-856260/&#34;   width=1280 height=&#34;720&#34;  /&gt;
    
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;To me, the biggest reason to switch was that all the newest and greatest features were coming to Python 3. My favourite top three exclusive features in Python 3 are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&#34;https://docs.python.org/3/library/asyncio.html&#34;&gt;&lt;strong&gt;asyncio&lt;/strong&gt;&lt;/a&gt;: One of the coolest technologies I picked up recently. The learning process is sometimes mind-bending. But the performance boost in the right situations is incredible.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&#34;https://docs.python.org/3/library/asyncio.html&#34;&gt;&lt;strong&gt;f-strings&lt;/strong&gt;&lt;/a&gt;: They are so incredibly expressive that you would want to use them everywhere. Instant love!&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&#34;https://docs.python.org/3/whatsnew/3.6.html#new-dict-implementation&#34;&gt;dict&lt;/a&gt;: New compact dict implementation which uses less memory and are ordered!&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Yes, &lt;a href=&#34;https://en.wikipedia.org/wiki/Fear_of_missing_out&#34;&gt;FOMO&lt;/a&gt; is real.&lt;/p&gt;
&lt;p&gt;Apart from my personal reasons, I would recommend everyone to migrate so that the community benefits from investing efforts into a common codebase. Plus we can all be consistent on which Python to recommend to beginners. &lt;a href=&#34;https://www.python.org/dev/peps/pep-0020/&#34;&gt;Because&lt;/a&gt;&amp;hellip;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;There should be one&amp;ndash; and preferably only one &amp;ndash;obvious way to do it.
Although that way may not be obvious at first unless you&amp;rsquo;re Dutch.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class=&#34;series-box&#34;&gt;
&lt;p&gt;This article contains an excerpt from the upcoming second edition of book &lt;a href=&#34;http://djangopatternsbook.github.io/&#34;&gt;&#34;Django Design Patterns and Best Practices&#34;&lt;/a&gt; by Arun Ravindran&lt;/p&gt;
&lt;/div&gt;
</description>
    </item>
    
    <item>
      <title>A Gentle Introduction to Creating a Minimal Hugo Site</title>
      <link>https://arunrocks.com/minimal-hugo-site-tutorial/</link>
      <pubDate>Mon, 10 Jul 2017 10:51:31 +0530</pubDate>
      
      <guid>https://arunrocks.com/minimal-hugo-site-tutorial/</guid>
      <description>&lt;p&gt;When I started using Hugo, I was very impressed by its speed. But I was daunted by the directory structure it creates for a new project. With directory names like &lt;code&gt;archetypes&lt;/code&gt; and &lt;code&gt;static&lt;/code&gt;, a Hugo site felt unfamiliar and confusing. Fortunately, not every site needs them.&lt;/p&gt;
&lt;p&gt;This post tells you how to start small with just the bare minimum files and directories to build a Hugo site without errors. Being minimal, this site will have only one page (essentially, the home page).&lt;/p&gt;
&lt;p&gt;You can see the finished project on &lt;a href=&#34;https://github.com/arocks/minimal-hugo&#34;&gt;Github&lt;/a&gt;. Let&amp;rsquo;s start looking at only the top-level files of the project:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.
├── config.toml
├── content/
├── .git/
├── .gitignore
└── themes/
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;There are only two directories: &lt;code&gt;content&lt;/code&gt; which contains your site&amp;rsquo;s content like posts or articles and &lt;code&gt;themes&lt;/code&gt; which are contain various themes - the non-content part of your site like its design and page layouts.&lt;/p&gt;
&lt;p&gt;For Hugo, &lt;code&gt;config.toml&lt;/code&gt; contains all the configuration settings of your site like the name of the site, author name, theme etc. For this minimal site, we will only mention two lines:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;baseURL = &amp;quot;http://example.org/&amp;quot;
theme = &amp;quot;bare&amp;quot;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This is a &lt;a href=&#34;https://en.wikipedia.org/wiki/TOML&#34;&gt;TOML file&lt;/a&gt;. It has a very simple syntax. Each line is written like this:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;key = &amp;quot;value&amp;quot;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;baseURL&lt;/code&gt; value mentions the URL where the site will be published. Strictly speaking, we don&amp;rsquo;t need it for a minimal site. But Hugo throws an error if &lt;code&gt;baseURL&lt;/code&gt; is not specified.&lt;/p&gt;
&lt;p&gt;Next, we mention that we are using the &amp;ldquo;bare&amp;rdquo; theme. Essentially, &amp;ldquo;bare&amp;rdquo; is a directory inside &amp;ldquo;themes&amp;rdquo; directory. We will look at it closely soon.&lt;/p&gt;
&lt;p&gt;The Git files are worth mentioning. I prefer to exclude the generated site (having rendered HTML pages) from Git. Assuming that the generated files will go into a directory named &amp;ldquo;public&amp;rdquo;, my &lt;code&gt;.gitignore&lt;/code&gt; file is simply this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;public
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;content-files&#34;&gt;Content files&lt;/h2&gt;
&lt;p&gt;A content file is usually a text file containing your blog post or article. Typically content files are written in Markdown syntax. But Hugo supports other text formats like Asciidoc, reStructuredText or Org-Mode, which gets converted to HTML. This is easier than directly editing HTML files.&lt;/p&gt;
&lt;p&gt;The only content file in this minimal site is &lt;code&gt;_index.md&lt;/code&gt;. This filename is special to Hugo and used to specify a page leading to a list of pages. Typically, an index file is used for a home page, a section, a taxonomy or a taxonomy terms listing.&lt;/p&gt;
&lt;p&gt;Our &lt;code&gt;_index.md&lt;/code&gt; looks like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-markdown&#34; data-lang=&#34;markdown&#34;&gt;+++
title = &amp;#34;Home sweet home&amp;#34;
+++

This page has &lt;span class=&#34;gs&#34;&gt;**bold**&lt;/span&gt; and &lt;span class=&#34;ge&#34;&gt;*italics*&lt;/span&gt; formatting.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The two &lt;code&gt;+++&lt;/code&gt; separators divides the document into two parts - the &lt;em&gt;front matter&lt;/em&gt; (first three lines) in TOML format and the rest of the document in Markdown format. Front matter specifies the metadata of the file like its title, date or category. Most text editors will treat this file as a Markdown file (due to the .md extension) and ignore the front matter.&lt;/p&gt;
&lt;p&gt;Since the &lt;code&gt;_index.md&lt;/code&gt; is located inside &lt;code&gt;content&lt;/code&gt; directory at the top-level, it will be the first page seen when the user opens the baseURL location i.e. the home page. However, for this page to be rendered, there must be a corresponding template within the theme.&lt;/p&gt;
&lt;h2 id=&#34;theme-files&#34;&gt;Theme files&lt;/h2&gt;
&lt;p&gt;So far, we have not specified the look and feel of the site. This is typically mentioned in a separate theme directory (it can also be mentioned inside a &lt;code&gt;layouts&lt;/code&gt; directory within the site but its more cleaner this way).&lt;/p&gt;
&lt;p&gt;Unlike say Wordpress themes, you might not be able to download an arbitrary Hugo theme and apply it to your site. This is because a theme makes certain assumptions like that your site is a blog and the posts are one-level deep etc, which might not be true in your case. So, I prefer making my own theme while creating new kind of sites. Besides you would eventually want to customize your theme anyway.&lt;/p&gt;
&lt;p&gt;The bare theme is located inside the themes directory. Here is directory structure of that theme:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;themes/
└── bare/
    ├── layouts/
    │   └── index.html
    └── theme.toml
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Note that this is literally a &amp;ldquo;bare&amp;rdquo; theme in that it has no stylesheets or images. It can just render a single home page in plain HTML.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;theme.toml&lt;/code&gt; like &lt;code&gt;config.toml&lt;/code&gt; contains some metadata about this theme. As seen below, it is fairly self-explanatory:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;name = &amp;quot;Bare&amp;quot;
license = &amp;quot;MIT&amp;quot;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The layouts directory contains templates which specify how your content files should be rendered into HTML. As you might have guessed, &lt;code&gt;index.html&lt;/code&gt; at the top-level is used for rendering a top-level &lt;code&gt;_index.md&lt;/code&gt;. This file contains:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;html&amp;gt;
  &amp;lt;body&amp;gt;
    &amp;lt;h1&amp;gt;Welcome!&amp;lt;/h1&amp;gt;

    &amp;lt;h2&amp;gt;{{ .Title }}&amp;lt;/h2&amp;gt;
    {{ .Content }}

  &amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This looks like an HTML page except for parts enclosed in double curly braces ( &lt;code&gt;{{ something }}&lt;/code&gt; ). These parts are in &lt;a href=&#34;https://gohugo.io/templates/go-templates/&#34;&gt;Go Template language&lt;/a&gt; and will be replaced by their values.&lt;/p&gt;
&lt;p&gt;To understand what &lt;code&gt;.Title&lt;/code&gt; means you have to understand that the dot in the beginning refers to the current context, which is the current page. In other programming languages this might be written as &lt;code&gt;ThisPage.Title&lt;/code&gt;, but here &lt;code&gt;ThisPage&lt;/code&gt; is implied and hence omitted.&lt;/p&gt;
&lt;p&gt;The value for &lt;code&gt;.Title&lt;/code&gt; comes from the front matter. While rendering &amp;ldquo;_index.md&amp;rdquo;, it will be replaced by &amp;ldquo;Home sweet home&amp;rdquo; (refer &lt;code&gt;_index.md&lt;/code&gt; mentioned earlier). The value for &lt;code&gt;.Content&lt;/code&gt; will be the rendered HTML from the Markdown file.&lt;/p&gt;
&lt;p&gt;Most themes will have certain common elements across a site like a header and footer. Just because we only need a template for one page, the &amp;ldquo;bare&amp;rdquo; theme omits all those flourishes.&lt;/p&gt;
&lt;p&gt;You can checkout the finished project at &lt;a href=&#34;https://github.com/arocks/minimal-hugo&#34;&gt;Github&lt;/a&gt;. You can use this as a landing page or could be a starting point to a larger Hugo project.&lt;/p&gt;
&lt;h2 id=&#34;rendering-and-publishing&#34;&gt;Rendering and Publishing&lt;/h2&gt;
&lt;p&gt;While developing a Hugo site or previewing a post that is being composed, you might want to use the built-in test server. The files are not generated (in the project folder) but you can browse your site locally in your browser&lt;/p&gt;
&lt;p&gt;For local development, execute the following command (in the project directory):&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ hugo server -w
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This is what you should see in your browser:&lt;/p&gt;
&lt;p&gt;&lt;figure&gt;
    &lt;img loading=&#34;lazy&#34; src=&#34;https://arunrocks.com/static/images/blog/minimal-site.png&#34; alt=&#34;Minimal site in hugo&#34;   width=475 height=&#34;370&#34;  /&gt;
    
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;Once you are ready to publish the site, you&amp;rsquo;ll need the generate the files into an output directory. The following command will create generate your site into the &amp;ldquo;public&amp;rdquo; directory:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ hugo --destination public
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now you can copy the files from public directory into the web root of &amp;ldquo;example.com&amp;rdquo; or whichever domain that you mentioned as your baseURL. You can use GitHub Pages to host this site for free. I would recommend reading up instructions in their &lt;a href=&#34;https://pages.github.com/&#34;&gt;GitHub Pages documentation&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Next, I would recommend looking at other Hugo sites to understand how various features of Hugo have been used. Personally, I wrote this post so that I have a minimal starting point when I start a new project. Enjoy exploring Hugo!&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Migrating Blogs (Again) from Pelican to Hugo</title>
      <link>https://arunrocks.com/moving-blogs-pelican-to-hugo/</link>
      <pubDate>Tue, 02 May 2017 10:51:31 +0530</pubDate>
      
      <guid>https://arunrocks.com/moving-blogs-pelican-to-hugo/</guid>
      <description>&lt;p&gt;Our universe is in a continuous cycle of creation and destruction. How can this humble site escape that cosmic dance? It is time to change the blogging platform of arunrocks.com again.&lt;/p&gt;
&lt;p&gt;You might remember my &lt;a href=&#34;https://arunrocks.com/moving-blogs-to-pelican/&#34;&gt;earlier lengthy justification of using Pelican&lt;/a&gt;. I have done numerous hacks and plugins to twist and bend it to my liking. While it has served me well for the past four years, it is time to move on.&lt;/p&gt;
&lt;p&gt;The reason, of course, is a much better static site generator - &lt;a href=&#34;http://gohugo.io/&#34;&gt;Hugo&lt;/a&gt;. A fairly young but very actively developed project, Hugo has some extremely compelling set of qualities, which made the choice to migrate my site fairly obvious. Some of them are:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Content Organization&lt;/strong&gt;: Hugo believes in the philosophy that your content should be arranged in the same way they are intended for the rendered website. This brings tremendous clarity in identifying file locations and reduces the need for hacks.&lt;/p&gt;
&lt;p&gt;By default, some blogging engines (including Pelican) assume that all your &amp;ldquo;pages&amp;rdquo; will be finally rendered into the &lt;code&gt;pages&lt;/code&gt; folder. A configuration setting can change it to use any URL scheme. But why doesn&amp;rsquo;t it leave it where it was? The source structure is nested and organized. Why flatten it and lose that information?&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Extremely Fast&lt;/strong&gt;: Even if your site contains hundreds of files, the build time is usually under a second, without cached compilation,&amp;hellip; inside a virtual machine, &amp;hellip; without an SSD. Yes, it is unbelievable.&lt;/p&gt;
&lt;p&gt;This makes the edit-preview development cycle a pleasure to use. Tweak an SCSS variable and the browser will live reload almost instantaneously. I make a hundred tweaks after a page gets rendered, so a short feedback loop is ideal for my workflow.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;No Stack&lt;/strong&gt;: This is usually marketed as the &amp;ldquo;single executable&amp;rdquo; advantage of Go applications. But it matters much more profoundly in the case of Hugo.&lt;/p&gt;
&lt;p&gt;Many new languages like Javascript and Python need a pile of third party libraries to make their tools run (even if they are &amp;ldquo;batteries included&amp;rdquo;). While it might be easy to setup initially with a single command like &lt;code&gt;pip install Foo&lt;/code&gt;, future invocations might need you to update everything to their latest versions first and then fixing whatever breaks.&lt;/p&gt;
&lt;p&gt;&lt;figure&gt;
    &lt;img loading=&#34;lazy&#34; src=&#34;https://arunrocks.com/static/images/blog/slacking-off-t-shirt-min.png&#34; alt=&#34;Slacking Off T shirt&#34;   width=618 height=&#34;505&#34;  /&gt;
    
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;Even though dynamic languages do not require a lengthy compilation step, a constant stream of updates can get tiring. &amp;ldquo;Updating my packages&amp;rdquo;&amp;quot; has become the new &amp;ldquo;I am compiling&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;Ok, end of my rant. Hugo is a single self contained executable (in all platforms). This not only reduces the number of moving pieces that you need to keep track of (my &lt;code&gt;requirements.txt&lt;/code&gt; for the site listed 20 packages), it simplifies the ongoing maintenance of your site.&lt;/p&gt;
&lt;p&gt;I would rather not have the headache of managing code environments just for writing a blog. In Arch Linux, where I develop my site, it is even easier considering it is a rolling distribution. Hugo automatically updates along with the rest of the system. The updates are usually backward compatible and nothing breaks.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Actively Developed&lt;/strong&gt;: Many static blog generator projects have this problem. The early days would have the community engaged and actively involved. Then the interest dwindles, code gets stale and the backlog of issues grows. Hugo is still in its early days and has a energetic community. Hopefully the interest will continue to grow.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Not too Blog-oriented&lt;/strong&gt;: My site, like most personal sites, is predominantly a blog. But it is not just a blog, it is a full-fledged site. Hugo has very minimal assumptions about what kind of site you have. For instance, I can convert a JSON file with all my talks into a Talks page. I just need to define a template for a new type of page in my layouts.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&#34;it-is-not-all-peaches-and-cream&#34;&gt;It is not all Peaches and Cream&lt;/h3&gt;
&lt;p&gt;Hugo does have some rough edges. But considering the rate of its development, you might find that all these problems have been solved by the time you read it. But, for the record, I did come across these issues:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Lack of Static Assets Pipeline&lt;/strong&gt;: I use SCSS to create my CSS files. In general, Hugo is unaware of any static assets pipeline which may involve compiling SCSS, minification or compression. I use a Makefile which invokes the compiler as a dependency for build. Sometimes I need to stop live reloading and explicitly call &lt;code&gt;Make&lt;/code&gt;. Since everything is fast, it doesn&amp;rsquo;t matter much.&lt;/p&gt;
&lt;p&gt;&lt;figure&gt;
    &lt;img loading=&#34;lazy&#34; src=&#34;https://arunrocks.com/static/images/blog/wasabi-conveyor-belt.jpg&#34; alt=&#34;Wasabi restaurant at Tysons Corner Center in McLean, Virginia taken by Ben Schumin&#34;   width=700 height=&#34;525&#34;  /&gt;
    
  &lt;/figure&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Menu Generation Flaky&lt;/strong&gt;: I found the &lt;a href=&#34;https://webdesignerhut.com/active-class-navigation-menu/&#34;&gt;&amp;ldquo;active section in menu&amp;rdquo; pattern&lt;/a&gt; used in most website menus a bit hard to implement. There are &lt;a href=&#34;https://discuss.gohugo.io/t/is-hasmenucurrent-for-list-of-content-templates/2609/6&#34;&gt;others&lt;/a&gt; &lt;a href=&#34;https://discuss.gohugo.io/t/questions-about-ismenucurrent-function-tag-names-keys-and-theme-contribution/945/8&#34;&gt;who&lt;/a&gt; &lt;a href=&#34;https://discuss.gohugo.io/t/normal-page-not-selectable-in-menu/5431&#34;&gt;have&lt;/a&gt; faced similar issues. I resorted to not using this pattern for now.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Outdated Blog posts&lt;/strong&gt; Hugo documentation is extensive and covers a lot of material. But good documentation is very hard to get right. Some sections are confusing and I often look for better explanations say from blogs.&lt;/p&gt;
&lt;p&gt;But one needs to watch out for outdated content. For instance, I needed to change my RSS feed location and one blog recommended changing &lt;code&gt;RSSUri&lt;/code&gt; in the config file. This is deprecated. Now, you need to use output formats say like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;outputFormats.RSS:
  BaseName: &amp;quot;index&amp;quot;
  Path: &amp;quot;feed/index.xml&amp;quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Python Tooling&lt;/strong&gt;: While using Pelican, I was happy that if I needed any additional functionality, I could always write a plugin in Python. This doesn&amp;rsquo;t worry me for two reasons. First, Hugo&amp;rsquo;s template system is very expressive and handles many of such needs. Second, &lt;a href=&#34;https://gohugo.io/extras/shortcodes/&#34;&gt;ShortCodes&lt;/a&gt; offer a much cleaner alternative to plugins.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Inconsistent Casing&lt;/strong&gt; Sometimes a variable is mentioned in title case in one place and lower case in another. I would end up wondering whether it is copyright or Copyright or CopyRight. Probably, there is a naming convention. But I haven&amp;rsquo;t found it yet.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;As you can see, most of these issues are solvable. Hugo is a long way from version 1.0 (currently we have v20.7). So this might all be fixed by then.&lt;/p&gt;
&lt;h3 id=&#34;changing-a-jet-engine-mid-flight&#34;&gt;Changing a Jet Engine Mid-flight&lt;/h3&gt;
&lt;p&gt;Once your site achieves a certain amount of traffic, then making any change is fraught with risk. Every time I change this site&amp;rsquo;s underlying platform I make a short TODO list. It looks something like this:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Setup Redirects&lt;/strong&gt;: Map the old link structure to the new ones&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Fix Renders&lt;/strong&gt;: Markdown is not quite a standard. Each Markdown engine has its own quirk. I manually check the rendered HTML is some cases.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Check Missing Images&lt;/strong&gt;: Things have to move around to adjust for various source layouts. So images, scripts or download links can return 404s.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Even after all these checks, I still need to watch the error log for omissions. As this happens in my spare time, the whole migration &amp;ldquo;project&amp;rdquo; takes months. It is pretty much like changing a jet&amp;rsquo;s engine mid-flight.&lt;/p&gt;
&lt;h3 id=&#34;some-takeaways&#34;&gt;Some Takeaways&lt;/h3&gt;
&lt;p&gt;In short, I would say you can never underestimate the sheer amount of work involved in migrating a site. There is a very &lt;a href=&#34;https://moz.com/blog/web-site-migration-guide-tips-for-seos&#34;&gt;good post on site migration&lt;/a&gt; by folks at Mozilla that covers many aspects that people tend to miss. Unless you have very good reasons to move, I would suggest that you stick with your blogging platform of choice.&lt;/p&gt;
&lt;p&gt;As for me, time to start thinking about migration to HTTPS 😉&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Hangman in more than three lines of Python</title>
      <link>https://arunrocks.com/hangman-more-than-three-lines-python-3/</link>
      <pubDate>Tue, 16 Feb 2016 20:03:00 +0530</pubDate>
      
      <guid>https://arunrocks.com/hangman-more-than-three-lines-python-3/</guid>
      <description>&lt;p&gt;Recently, &lt;a href=&#34;http://danverbraganza.com/writings/hangman-in-3-lines-of-python&#34;&gt;Danver wrote about a brilliant implementation of the Hangman game&lt;/a&gt; in just three lines of Python. But the shortened code might be hard to understand. In this post we will rewrite his code in a more idiomatic Python 3 style.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Spoiler Alert: If you prefer a fun exercise, try doing it yourself first and then compare with my version.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Danver&amp;rsquo;s implementation cleverly uses the system dictionary (pre-installed in Linux and Mac, but we&amp;rsquo;ll see how it can work in Windows too) for picking a random word. It also displays a neat ASCII-art hangman at every step. Except for a few minor improvements, I have tried to retain the essence of Danver&amp;rsquo;s original in my rewrite below.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# -*- coding: utf-8 -*-&lt;/span&gt;
&lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&amp;#34;A simple text-based game of hangman
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;A re-implementation of Hangman 3-liner in more idiomatic Python 3
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;Original: http://danverbraganza.com/writings/hangman-in-3-lines-of-python
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;Requirements:
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;  A dictionary file at /usr/share/dict/words
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;Usage:
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;  $ python hangman.py
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;Released under the MIT License. (Re)written by Arun Ravindran http://arunrocks.com
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;

&lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;random&lt;/span&gt;

&lt;span class=&#34;n&#34;&gt;DICT&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;/usr/share/dict/words&amp;#39;&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;chosen_word&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;random&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;choice&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;open&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;DICT&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;readlines&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;())&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;upper&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;strip&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;guesses&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;scaffold&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&amp;#34;
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;|======
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;|   |
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;| {3} {0} {5}
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;|  {2}{1}{4}
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;|  {6} {7}
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;|  {8} {9}
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;|
&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;man&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;list&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;OT-&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\\&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;-//&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\\&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;||&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;guesses_left&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;len&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;man&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;

&lt;span class=&#34;k&#34;&gt;while&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;not&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;guesses&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;issuperset&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;chosen_word&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;and&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;guesses_left&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
    &lt;span class=&#34;k&#34;&gt;print&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;{} ({} guesses left)&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;format&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;,&amp;#39;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;join&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;sorted&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;guesses&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)),&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;guesses_left&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;
    &lt;span class=&#34;k&#34;&gt;print&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;scaffold&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;format&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;man&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[:&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;guesses_left&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39; &amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;guesses_left&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)))&lt;/span&gt;
    &lt;span class=&#34;k&#34;&gt;print&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39; &amp;#39;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;join&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;letter&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;letter&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;guesses&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;else&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;_&amp;#39;&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;letter&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;chosen_word&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;guesses&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;update&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;c&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;upper&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;c&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;input&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;str&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;isalpha&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;c&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;guesses_left&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;max&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;len&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;man&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;len&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;guesses&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;chosen_word&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)),&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;

&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;guesses_left&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
    &lt;span class=&#34;k&#34;&gt;print&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;You win!&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;else&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
    &lt;span class=&#34;k&#34;&gt;print&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;You lose!&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;{}&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;HANGED!&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;format&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;scaffold&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;format&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;man&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)))&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;print&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;Word was&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;chosen_word&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You can view or download the &lt;a href=&#34;https://gist.github.com/arocks/173ef7d0e2b3d18b6e97&#34;&gt;gist on Github&lt;/a&gt; as well.&lt;/p&gt;
&lt;h3 id=&#34;ho_-it-_orks&#34;&gt;HO_ IT _ORKS&lt;/h3&gt;
&lt;p&gt;The code makes excellent use of Python&amp;rsquo;s built-in &lt;a href=&#34;https://docs.python.org/3.1/tutorial/datastructures.html#sets&#34;&gt;&lt;code&gt;set&lt;/code&gt;&lt;/a&gt; data structure and string &lt;a href=&#34;https://pyformat.info/&#34;&gt;&lt;code&gt;format&lt;/code&gt;&lt;/a&gt; function.&lt;/p&gt;
&lt;p&gt;Right after a boring module &lt;a href=&#34;https://www.python.org/dev/peps/pep-0257/&#34;&gt;docstring&lt;/a&gt; and the &lt;code&gt;import&lt;/code&gt; statement, we initialize the following variables:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;DICT&lt;/strong&gt;: Path to a dictionary file&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;chosen_word&lt;/strong&gt;: Randomly picked line (aka. a word) from DICT&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;guesses&lt;/strong&gt;: Set of letters guessed by the user, so far&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;scaffold&lt;/strong&gt;: Hangman drawn in ASCII art as a format string&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;man&lt;/strong&gt;: Missing ASCII characters for &lt;code&gt;scaffold&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;guesses_left&lt;/strong&gt;: Remaining letter guesses&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The &lt;code&gt;while&lt;/code&gt; loop, whose exit condition will be explained soon, is our main game loop. The first &lt;code&gt;print&lt;/code&gt; function reminds you the guesses you have entered so far (in alphabetic order) and the number of guesses left. The next &lt;code&gt;print&lt;/code&gt; function shows the ASCII hangman with enough missing parts from &lt;code&gt;man&lt;/code&gt; based on the number of wrong guesses.&lt;/p&gt;
&lt;p&gt;Finally, the third &lt;code&gt;print&lt;/code&gt; function shows the &lt;code&gt;chosen_word&lt;/code&gt; by revealing only the characters from your &lt;code&gt;guesses&lt;/code&gt; and replacing the rest with underscores. In the following line, we read a character or even several characters from the user, uppercase them, filter out the non-alphabets and update the &lt;code&gt;guesses&lt;/code&gt; set, all in a single line:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;guesses.update(c.upper() for c in input() if str.isalpha(c))
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Next, we calculate the number of letters we got wrong. As the diagram below shows, this is the difference of the sets &lt;code&gt;guesses&lt;/code&gt; and &lt;code&gt;chosen_words&lt;/code&gt; (In the diagram, the letters - C,M,T). We find how many guesses are left by subtracting the set of letters of &lt;code&gt;man&lt;/code&gt; from the letters we got wrong. The &lt;code&gt;max&lt;/code&gt; function ensures that we don&amp;rsquo;t go below zero.&lt;/p&gt;
&lt;p&gt;&lt;figure&gt;
    &lt;img loading=&#34;lazy&#34; src=&#34;https://arunrocks.com/static/images/blog/hangman-venn.png&#34; alt=&#34;Hangman logic explained through sets&#34;   width=750 height=&#34;250&#34;  /&gt;
    
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;Eventually, you could win if your guesses cover all the right letters. In the language of sets, this is when &lt;code&gt;guesses&lt;/code&gt; set grows large enough to become a super set of &lt;code&gt;chosen_word&lt;/code&gt; set. This is indicated by the dashed purple circle. Hence, the &lt;code&gt;while&lt;/code&gt; loop will continue until this happens or we run out of remaining guesses.&lt;/p&gt;
&lt;p&gt;Finally, we show a win or lose message based on whether we ran out of guesses. In either case we reveal the initial &lt;code&gt;chosen_word&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&#34;impro_emen_s&#34;&gt;IMPRO_EMEN_S&lt;/h3&gt;
&lt;p&gt;For comparison, here is Danver&amp;rsquo;s original three-liner:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;n&#34;&gt;license&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;chosen_word&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;guesses&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;scaffold&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;man&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;guesses_left&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;https://opensource.org/licenses/MIT&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;join&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;filter&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;str&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;isalpha&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;__import__&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;random&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;choice&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;open&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;/usr/share/dict/words&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;readlines&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;())&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;upper&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;())),&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(),&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;|======&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;|   |&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;| {3} {0} {5}&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;|  {2}{1}{4}&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;|  {6} {7}&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;|  {8} {9}&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;|&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;list&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;OT-&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\\&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;-//&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\\&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;||&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;10&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;while&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;not&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;all&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;letter&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;guesses&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;letter&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;chosen_word&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;and&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;guesses_left&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;_&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;guesses_left&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;map&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;guesses&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;add&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;filter&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;str&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;isalpha&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;raw_input&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;%s&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;%s&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt; guesses left)&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;%s&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;%s&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;:&amp;#39;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;%&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;,&amp;#39;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;join&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;sorted&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;guesses&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)),&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;guesses_left&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;scaffold&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;format&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;man&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[:&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;10&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;guesses_left&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39; &amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;guesses_left&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)),&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39; &amp;#39;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;join&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;letter&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;letter&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;guesses&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;else&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;_&amp;#39;&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;letter&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;chosen_word&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)))&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;upper&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;())),&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;max&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;((&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;10&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;len&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;guesses&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;chosen_word&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))),&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;print&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;You&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;lose!&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;scaffold&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;format&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;man&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;win!&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;][&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;bool&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;guesses_left&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)],&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;Word was&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;chosen_word&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Got it? Okay, maybe it needs a bit of explanation. Python is a whitespace-aware language designed for maximum readability. So it takes a lot of questionable tricks to write one-liners, some of which I have used myself in my post &lt;a href=&#34;http://arunrocks.com/python-one-liner-games/&#34;&gt;&amp;ldquo;Python One-liner Games&amp;rdquo;&lt;/a&gt;. This time we are going in the opposite direction.&lt;/p&gt;
&lt;p&gt;Probably, the most visible changes are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;License&lt;/strong&gt;: Mentioned in a doc string rather than as a string&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Import&lt;/strong&gt;: No longer need to use the internal &lt;code&gt;__import__&lt;/code&gt; function&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Scaffold&lt;/strong&gt;: Multi-line string rather than a one-liner&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Print&lt;/strong&gt;: Changed from a statement to a function, as in Python 3&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Raw_input&lt;/strong&gt;: Changed to an &lt;code&gt;input&lt;/code&gt; function, as in Python 3&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;C-style %s formats&lt;/strong&gt;: Replaced with &lt;code&gt;str.format&lt;/code&gt; everywhere&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;But, there are also some less evident code changes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Loop condition&lt;/strong&gt;: Replaced list comprehension in &lt;code&gt;while&lt;/code&gt; condition with a superset check&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Negative index&lt;/strong&gt;: No need of &lt;code&gt;man[:10-guesses_left]&lt;/code&gt;, just &lt;code&gt;man[:-guesses_left]&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Set update&lt;/strong&gt;: Replace &lt;code&gt;map&lt;/code&gt;/&lt;code&gt;filter&lt;/code&gt; with a &lt;code&gt;set.update&lt;/code&gt; i.e. from this:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;    map(guesses.add, filter(str.isalpha, raw_input...

with this:

    guesses.update(c.upper() for c in input() if str.isalpha(c))
&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Magic numbers&lt;/strong&gt;: The number 10 is no longer hard-coded and replaced with &lt;code&gt;len(man)&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As you can see, I have preferred set functions over list comprehensions. The choice of set functions like &lt;code&gt;my_set.update&lt;/code&gt; over set operators like &lt;code&gt;my_set +=&lt;/code&gt; was intentional as the former allows any iterable as an argument and not just sets. In most cases, I have used &lt;a href=&#34;https://docs.python.org/2/reference/expressions.html#generator-expressions&#34;&gt;generator expressions&lt;/a&gt; for efficiency.&lt;/p&gt;
&lt;h3 id=&#34;w_y-pyt_on-3&#34;&gt;W_Y PYT_ON 3?&lt;/h3&gt;
&lt;p&gt;I must admit that the actual reason I rewrote the Hangman was because it didn&amp;rsquo;t work on my Arch Linux box, which runs on Python 3. Over the last few months, I have completely switched over all my projects (and &lt;a href=&#34;http://djangopatternsbook.github.io/&#34;&gt;my book&lt;/a&gt;) to Python 3. So far I have had no reason to complain.&lt;/p&gt;
&lt;p&gt;Apart from the syntactic differences, you will find some solid advantages of using Python 3 versus Python 2:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Unicode files&lt;/strong&gt;: Since the dictionary file path can be changed, I created a test file with a few &lt;a href=&#34;https://en.wikipedia.org/wiki/Malayalam&#34;&gt;Malayalam&lt;/a&gt; words in separate lines. The Python 2 version just exits with a win message. This is probably because &lt;code&gt;str.isalpha&lt;/code&gt; filters out all the characters. Whereas, in Python 3, everything just works.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Removes arcane forms&lt;/strong&gt;: No more &lt;code&gt;raw_input&lt;/code&gt; (who uses the old &lt;code&gt;input&lt;/code&gt;?) or &lt;code&gt;print&lt;/code&gt; statements&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;If you are on Windows, you can download pretty much &lt;a href=&#34;https://github.com/buddingmonkey/WordGameDictionary/raw/master/Dictionaries/ospd.txt&#34;&gt;any of&lt;/a&gt; the &lt;a href=&#34;https://github.com/Glutanimate/wordlist-medicalterms-en/raw/master/wordlist.txt&#34;&gt;dictionaries online&lt;/a&gt; (even the &lt;a href=&#34;http://www.cs.cmu.edu/~biglou/resources/bad-words.txt&#34;&gt;offensive&lt;/a&gt; ones) and change the path in &lt;code&gt;DICT&lt;/code&gt; to something like &lt;code&gt;dict.txt&lt;/code&gt;. Or, you can create a simple text file with one word on each line. Pro Tip: Hangman is great for learning foreign languages so try creating a Unicode file with some foreign language words.&lt;/p&gt;
&lt;p&gt;Before any of the Python 2 fans lash out on me, let me note in the passing that this code will work perfectly on Python 2.7+ if you replace &lt;code&gt;input&lt;/code&gt; with &lt;code&gt;raw_input&lt;/code&gt;. Cheers!&lt;/p&gt;
&lt;h3 id=&#34;fi_al-comme_t&#34;&gt;FI_AL COMME_T&lt;/h3&gt;
&lt;p&gt;This post is by no means a critique of Danver&amp;rsquo;s code. In fact, I loved his implementation and totally didn&amp;rsquo;t waste my weekend playing Hangman (27 wins out of 30 games!!!). It had a lot of fun mapping the problem to sets and making small improvements.&lt;/p&gt;
&lt;p&gt;Hope you found some new Python best practices or just an awesome word game to kill time!&lt;/p&gt;
</description>
    </item>
    
  </channel>
</rss>
