<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Tushar Sadhwani</title>
    <description>The latest articles on Forem by Tushar Sadhwani (@tusharsadhwani).</description>
    <link>https://forem.com/tusharsadhwani</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F461559%2F08ceb6fc-9f84-4112-bac6-98fb4ef7a3a0.jpg</url>
      <title>Forem: Tushar Sadhwani</title>
      <link>https://forem.com/tusharsadhwani</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/tusharsadhwani"/>
    <language>en</language>
    <item>
      <title>The math behind Python's slices</title>
      <dc:creator>Tushar Sadhwani</dc:creator>
      <pubDate>Thu, 02 Sep 2021 17:23:29 +0000</pubDate>
      <link>https://forem.com/tusharsadhwani/the-math-behind-python-s-slices-1j1f</link>
      <guid>https://forem.com/tusharsadhwani/the-math-behind-python-s-slices-1j1f</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Read the original post on &lt;a href="https://sadh.life/posts/slices"&gt;my blog&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The basics
&lt;/h2&gt;

&lt;p&gt;Let's get the basics out of the way first:&lt;/p&gt;

&lt;p&gt;Slicing in Python is a way to easily extract a section of a list.&lt;/p&gt;

&lt;p&gt;The simplest form of a slice only considers the first two parts, a &lt;code&gt;start&lt;/code&gt; index and an &lt;code&gt;end&lt;/code&gt; index. Not providing either the start or the end will result in you getting all the numbers from the beginning and/or the end.&lt;/p&gt;

&lt;p&gt;Like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;nums&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;[:&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;:]&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Note that the &lt;code&gt;end&lt;/code&gt; index, when provided, is never included in the result.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And just for completion's sake, if you don't provide either, it just clones the entire list:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;[:]&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Apart from these, there's also a third argument: &lt;code&gt;step&lt;/code&gt;, which tells how many numbers it should increment its index by, to get to the next element. &lt;code&gt;step&lt;/code&gt; is 1 by default.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;nums&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;[::&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;[::&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;[::&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The interesting bits
&lt;/h2&gt;

&lt;p&gt;You can imagine the slicing algorithm being used by the interpreter to be as following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;stop&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;stop&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
        &lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;step&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This explains the behaviour of &lt;code&gt;end&lt;/code&gt; never being included, and how &lt;code&gt;step&lt;/code&gt; decides how to pick the next value.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;But,&lt;/strong&gt; how about this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;[:&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;[:&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;[]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What's going on in here?&lt;/p&gt;

&lt;h2&gt;
  
  
  Negative numbers in slices
&lt;/h2&gt;

&lt;p&gt;It should be common knowledge that you can provide negative &lt;strong&gt;indices&lt;/strong&gt; in Python to get a number from the end:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;nums&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;  &lt;span class="c1"&gt;# last index
&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;  &lt;span class="c1"&gt;# second from the end
&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;  &lt;span class="c1"&gt;# it's the same thing
&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Well, the same thing happens in slices as well:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If you give it a negative &lt;code&gt;start&lt;/code&gt; or &lt;code&gt;stop&lt;/code&gt; value, it will be treated as that same index from the end.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Like, all of these 3 mean the same thing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;  &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;   &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;  &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And once you know this, &lt;em&gt;it's simple math&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;[:&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;    &lt;span class="c1"&gt;# all values except the last one
&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;[:&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;    &lt;span class="c1"&gt;# all values except the last three
&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;:]&lt;/span&gt;  &lt;span class="c1"&gt;# all values from last 3rd
&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And here's an updated &lt;code&gt;slice&lt;/code&gt; Python function that factors this in:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;stop&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;stop&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;stop&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;stop&lt;/span&gt;

    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;stop&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
        &lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;step&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Negative &lt;code&gt;step&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Now the only thing we haven't covered in the examples above is a negative &lt;code&gt;step&lt;/code&gt; value. I'm sure you must have seen this one rather un-intuitive way to reverse a list in Python:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;[::&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What's going on here?&lt;/p&gt;

&lt;p&gt;Well, essentially whenever the step value is negative, Python starts iterating from behind. Essentially, the default start value becomes the &lt;strong&gt;end&lt;/strong&gt; of the array and the default stop value becomes the &lt;strong&gt;start&lt;/strong&gt; of the array.&lt;/p&gt;

&lt;p&gt;And you can change those, of course, which is how this works:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;   &lt;span class="c1"&gt;# will get indices 2, 1 and 0
&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now herein lies the second important note about slices: When &lt;code&gt;step&lt;/code&gt; is negative, the condition that's used to determine whether to take the next element or not is &lt;strong&gt;flipped around&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;It makes intuitive sense if you think about it for a moment, if we are checking &lt;code&gt;while start &amp;lt; end&lt;/code&gt; while also decrementing &lt;code&gt;start&lt;/code&gt; at every step, we will never reach the point where the condition becomes false. So we &lt;em&gt;need&lt;/em&gt; to flip the condition around to &lt;code&gt;while start &amp;gt; end&lt;/code&gt;, in order for slicing to still work.&lt;/p&gt;

&lt;p&gt;That explains why &lt;code&gt;nums[-1:-3:-1]&lt;/code&gt; returns &lt;code&gt;[6, 5]&lt;/code&gt;, it's because it starts with the last index, and keeps going until it's decremented till the 3rd last index (which is excluded).&lt;/p&gt;

&lt;p&gt;If you want an updated Python code that factors this in, here it is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;stop&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;stop&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;stop&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;stop&lt;/span&gt;

    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;step&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;stpp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
            &lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;step&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="c1"&gt;# Negative slice
&lt;/span&gt;        &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;stop&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
            &lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;step&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;But what about &lt;code&gt;nums[-1:-3]&lt;/code&gt; returning an empty list?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Well that's easy. Since -1 points to the end of the array, and step is 1 (positive), therefore &lt;code&gt;start &amp;lt; end&lt;/code&gt; is &lt;code&gt;False&lt;/code&gt; from the get go, and the result just stays empty.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;Hopefully it is evident that Python's slices are rather straightforward, once you understand a couple basic concepts about how they function.&lt;/p&gt;

&lt;p&gt;Also note, that my &lt;code&gt;slice&lt;/code&gt; function isn't an exact implementation of the algorithm, though it comes close. Currently it has no way of &lt;em&gt;not&lt;/em&gt; specifying a start or an end, and it also creates an infinite loop for &lt;code&gt;step=0&lt;/code&gt;. But apart from that, it's pretty much identical to the Python builtin slice implementation.&lt;/p&gt;

&lt;p&gt;So that's pretty much all the math behind Python slices, and how they work under the hood. ✨&lt;/p&gt;

</description>
      <category>python</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>What the f-strings?</title>
      <dc:creator>Tushar Sadhwani</dc:creator>
      <pubDate>Wed, 07 Jul 2021 21:54:19 +0000</pubDate>
      <link>https://forem.com/tusharsadhwani/what-the-f-strings-391c</link>
      <guid>https://forem.com/tusharsadhwani/what-the-f-strings-391c</guid>
      <description>&lt;p&gt;So a couple months ago, I wrote a &lt;a href="https://dev.to/tusharsadhwani/the-comprehensive-guide-to-mypy-561m"&gt;comprehensive blog on mypy&lt;/a&gt;. Today I'm planning to do the same with f-strings, putting everything I know about them into a single source of knowledge. It's an awesome Python feature, and I hope you'll get to learn something new about it ✨&lt;/p&gt;

&lt;h2&gt;
  
  
  Index
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;What is an f-string?&lt;/li&gt;
&lt;li&gt;Simple examples&lt;/li&gt;
&lt;li&gt;A brief history of string formatting&lt;/li&gt;
&lt;li&gt;Why f-strings&lt;/li&gt;
&lt;li&gt;
More examples

&lt;ul&gt;
&lt;li&gt;Padding / truncating&lt;/li&gt;
&lt;li&gt;Alignment&lt;/li&gt;
&lt;li&gt;Rounding numbers&lt;/li&gt;
&lt;li&gt;Converting types&lt;/li&gt;
&lt;li&gt;Adding commas to large numbers&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;
Special syntax

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;!s&lt;/code&gt;, &lt;code&gt;!r&lt;/code&gt; and &lt;code&gt;!a&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;{x=}&lt;/code&gt; syntax&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;datetime&lt;/code&gt; formatting&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Nested formatting&lt;/li&gt;
&lt;li&gt;Custom formatting using &lt;code&gt;__format__&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Limitations&lt;/li&gt;
&lt;li&gt;Conclusion&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What is an f-string?
&lt;/h2&gt;

&lt;p&gt;"f-strings" are a feature added to Python in version 3.6, and it's essentially a new, more concise way to embed values inside strings.&lt;/p&gt;

&lt;p&gt;They're called f-strings because of the syntax: you put an &lt;code&gt;f&lt;/code&gt; before the string literal, like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;string&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s"&gt;'this is an f-string'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Simple examples
&lt;/h2&gt;

&lt;p&gt;Here's a few basic examples on how to use f-strings to get you started:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;birth_year&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'Tushar'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2000&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s"&gt;'I am &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;, and I was born in &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;birth_year&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;I&lt;/span&gt; &lt;span class="n"&gt;am&lt;/span&gt; &lt;span class="n"&gt;Tushar&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;I&lt;/span&gt; &lt;span class="n"&gt;was&lt;/span&gt; &lt;span class="n"&gt;born&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="mi"&gt;2000&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;now&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s"&gt;'I am &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;year&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;birth_year&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; years old'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;I&lt;/span&gt; &lt;span class="n"&gt;am&lt;/span&gt; &lt;span class="mi"&gt;21&lt;/span&gt; &lt;span class="n"&gt;years&lt;/span&gt; &lt;span class="n"&gt;old&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;age&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;year&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;birth_year&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s"&gt;'I am &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"an adult"&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;age&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;18&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="s"&gt;"a child"&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;.'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;I&lt;/span&gt; &lt;span class="n"&gt;am&lt;/span&gt; &lt;span class="n"&gt;an&lt;/span&gt; &lt;span class="n"&gt;adult&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  A brief history of string formatting
&lt;/h2&gt;

&lt;p&gt;String formatting in Python dates back a long time. The original formatting using the &lt;code&gt;%&lt;/code&gt; sign has existed in Python ever since version 1.x (and even before that in C, which is where this feature's inspiration comes from). It allowed you to do most string formatting very easily, even though the syntax was a bit unusual: it uses &lt;code&gt;%&lt;/code&gt; flags in your string, which get replaced by the values you pass in. Here's an example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;city&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'London'&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'She lives in %s since %d'&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;city&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2000&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="n"&gt;She&lt;/span&gt; &lt;span class="n"&gt;lives&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;London&lt;/span&gt; &lt;span class="n"&gt;since&lt;/span&gt; &lt;span class="mi"&gt;2000&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There's a bunch of these &lt;code&gt;%&lt;/code&gt; patterns, and each of them has a meaning:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;%s&lt;/code&gt; - String&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;%c&lt;/code&gt; - Character (ASCII/Unicode)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;%d&lt;/code&gt; - Digits (Integer)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;%f&lt;/code&gt; - Floats&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;%x&lt;/code&gt; - Hexadecimal number, etc.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each of these can be modified with more information, like padding and alignment, for example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;%9s&lt;/code&gt; means a string of length 9.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;%-7d&lt;/code&gt; means an integer of length 7, but &lt;strong&gt;left-aligned&lt;/strong&gt;.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'%15f seconds'&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mf"&gt;31.415926&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="mf"&gt;31.415926&lt;/span&gt; &lt;span class="n"&gt;seconds&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'%-15f seconds'&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mf"&gt;31.415926&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="mf"&gt;31.415926&lt;/span&gt;       &lt;span class="n"&gt;seconds&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Eventually, people realised that the &lt;code&gt;%&lt;/code&gt; syntax borrowed from C might not be the most readable way to format strings. So in Python 3.0 (alongside 2.6), A new method was added to the &lt;code&gt;str&lt;/code&gt; data type: &lt;code&gt;str.format&lt;/code&gt;. Not only was it more obvious in what it was doing, it added a bunch of new features, like dynamic data types, center alignment, index-based formatting, and specifying padding characters. Here's a few examples:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;month&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'May'&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'I was born in {}.'&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;month&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="n"&gt;I&lt;/span&gt; &lt;span class="n"&gt;was&lt;/span&gt; &lt;span class="n"&gt;born&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;May&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;blog_title&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'What the f-string?'&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'{title:-^30}'&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;blog_title&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="o"&gt;------&lt;/span&gt;&lt;span class="n"&gt;What&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;&lt;span class="o"&gt;------&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'{:_&amp;lt;15f} seconds'&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;31.415926&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="mf"&gt;31.415926&lt;/span&gt;&lt;span class="n"&gt;______&lt;/span&gt; &lt;span class="n"&gt;seconds&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'{:&amp;gt;15f} seconds'&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;31.415926&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
      &lt;span class="mf"&gt;31.415926&lt;/span&gt; &lt;span class="n"&gt;seconds&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Note that if you don't specify an alignment character using &lt;code&gt;&amp;lt;&lt;/code&gt;, &lt;code&gt;&amp;gt;&lt;/code&gt; or &lt;code&gt;^&lt;/code&gt;, it will &lt;em&gt;always&lt;/em&gt; default to left alignment. This is different from &lt;code&gt;%&lt;/code&gt;-formatting, as that defaults to right-alignment for numbers.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Along with &lt;code&gt;str.format&lt;/code&gt; method, there's also a built-in &lt;code&gt;format&lt;/code&gt; function which does the same thing.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;For a lot more information about &lt;code&gt;%&lt;/code&gt;-formatting and &lt;code&gt;str.format&lt;/code&gt;, and all of their (many) features, head to &lt;a href="https://pyformat.info"&gt;pyformat.info&lt;/a&gt;. It is very useful as a reference for the features and syntax.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Why f-strings?
&lt;/h2&gt;

&lt;p&gt;One thing that you should know is that &lt;code&gt;str.format()&lt;/code&gt; can already do &lt;em&gt;(almost)&lt;/em&gt; everything that f-strings can do. You might be wondering then, "why were f-strings created in the firt place? And why should &lt;em&gt;I&lt;/em&gt; care about them?"&lt;/p&gt;

&lt;p&gt;Well, it's for two reasons: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;it's &lt;strong&gt;way more intuitive&lt;/strong&gt;, and&lt;/li&gt;
&lt;li&gt;it's &lt;strong&gt;way more readable&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here's a comparision:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;age&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'Mark'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;31&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="c1"&gt;# str.format version
&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'Hi, I'&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;I&lt;/span&gt;&lt;span class="s"&gt;'m {1} years old.'&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;age&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;Hi&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;I&lt;/span&gt;&lt;span class="s"&gt;'m Mark and I'&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="mi"&gt;31&lt;/span&gt; &lt;span class="n"&gt;years&lt;/span&gt; &lt;span class="n"&gt;old&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="c1"&gt;# f-string version
&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s"&gt;'Hi, I'&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;I&lt;/span&gt;&lt;span class="s"&gt;'m {age} years old.'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;Hi&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;I&lt;/span&gt;&lt;span class="s"&gt;'m Mark and I'&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="mi"&gt;31&lt;/span&gt; &lt;span class="n"&gt;years&lt;/span&gt; &lt;span class="n"&gt;old&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These two properties, of being intuitive and readable, are part of the core philisophy of Python (refer &lt;a href="https://www.python.org/dev/peps/pep-0020/"&gt;The Zen of Python&lt;/a&gt;).&lt;/p&gt;

&lt;h2&gt;
  
  
  More Examples
&lt;/h2&gt;

&lt;p&gt;Now, a few examples on everything that you can do with f-strings.&lt;/p&gt;

&lt;h3&gt;
  
  
  Padding / truncating
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;pi&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;3.141592&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;pi&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="mf"&gt;3.141592&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;pi&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;     &lt;span class="c1"&gt;# padding to make length 10
&lt;/span&gt;  &lt;span class="mf"&gt;3.141592&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;pi&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;010&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;    &lt;span class="c1"&gt;# padding with zeroes
&lt;/span&gt;&lt;span class="mf"&gt;003.141592&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;pi&lt;/span&gt;&lt;span class="p"&gt;:.&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;     &lt;span class="c1"&gt;# 3 digits total, ignoring decimal
&lt;/span&gt;&lt;span class="mf"&gt;3.14&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;string&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Hello! this is a string"&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;:.&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# 6 characters
&lt;/span&gt;&lt;span class="s"&gt;'Hello!'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Alignment
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;heading&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'Test'&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;heading&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="n"&gt;Test&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;heading&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;~&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# specify alignment for custom padding
&lt;/span&gt;&lt;span class="o"&gt;~~~~~~~~~~~~~~~~&lt;/span&gt;&lt;span class="n"&gt;Test&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;heading&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;Test________________&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;heading&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;=^&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;========&lt;/span&gt;&lt;span class="n"&gt;Test&lt;/span&gt;&lt;span class="o"&gt;========&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Rounding numbers
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;num&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;2.136&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;num&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="mf"&gt;2.136&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;num&lt;/span&gt;&lt;span class="p"&gt;:.&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# Rounded up
&lt;/span&gt;&lt;span class="mf"&gt;2.14&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;num&lt;/span&gt;&lt;span class="p"&gt;:.&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# Rounded down
&lt;/span&gt;&lt;span class="mf"&gt;2.1&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Converting types
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;       &lt;span class="c1"&gt;# int to ascii
&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;604&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;      &lt;span class="c1"&gt;# int to float
&lt;/span&gt;&lt;span class="mf"&gt;604.000000&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;84&lt;/span&gt;&lt;span class="p"&gt;:.&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;%'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="mf"&gt;84.00&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;604&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;      &lt;span class="c1"&gt;# int to hex
&lt;/span&gt;&lt;span class="mi"&gt;25&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;604&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;      &lt;span class="c1"&gt;# int to binary
&lt;/span&gt;&lt;span class="mi"&gt;1001011100&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;604&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# int to binary, with zero-padding
&lt;/span&gt;&lt;span class="mi"&gt;0000001001011100&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Adding commas to large numbers
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;large_num&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;12_345_678&lt;/span&gt;  &lt;span class="c1"&gt;# int syntax supports underscores :D
&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;large_num&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="mi"&gt;12345678&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;large_num&lt;/span&gt;&lt;span class="p"&gt;:,&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;345&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;678&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Special syntax
&lt;/h2&gt;

&lt;p&gt;There's a few special set of syntaxes that don't exist in the original &lt;code&gt;%&lt;/code&gt;-formatting:&lt;/p&gt;

&lt;h3&gt;
  
  
  !s !r and !a
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;datetime&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;                &lt;span class="c1"&gt;# repr value
&lt;/span&gt;&lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2021&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;21&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;56&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;698285&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;         &lt;span class="c1"&gt;# str value
&lt;/span&gt;&lt;span class="mi"&gt;2021&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;07&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;06&lt;/span&gt; &lt;span class="mi"&gt;02&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;22&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;02.772826&lt;/span&gt;     
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;    &lt;span class="c1"&gt;# str value by default
&lt;/span&gt;&lt;span class="mi"&gt;2021&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;07&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;06&lt;/span&gt; &lt;span class="mi"&gt;02&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;22&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;14.357562&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="err"&gt;!&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# repr value
&lt;/span&gt;&lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2021&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;22&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;17&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;709937&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="err"&gt;!&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# str value
&lt;/span&gt;&lt;span class="mi"&gt;2021&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;07&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;06&lt;/span&gt; &lt;span class="mi"&gt;02&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;22&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;20.081837&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;sparkles&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'✨'&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;sparkles&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="err"&gt;✨&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;sparkles&lt;/span&gt;&lt;span class="err"&gt;!&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;        &lt;span class="c1"&gt;# ascii-safe value
&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="se"&gt;\u2728&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;code&gt;datetime&lt;/code&gt; formatting
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;datetime&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;B&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;Y&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;Tuesday&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;July&lt;/span&gt; &lt;span class="mi"&gt;06&lt;/span&gt; &lt;span class="mi"&gt;2021&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;For more info on the &lt;code&gt;%&lt;/code&gt; codes specifically for datetime objects, check out the documentation for &lt;code&gt;datetime.strftime&lt;/code&gt;, or check out &lt;a href="https://strftime.org"&gt;strftime.org&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;{x=}&lt;/code&gt; syntax
&lt;/h3&gt;

&lt;p&gt;This is a new syntax that was added to Python 3.8, and it helps you quickly print out a variable's value, usually for debugging purposes. Essentially, &lt;code&gt;f'{abc=}'&lt;/code&gt; is the same as &lt;code&gt;f'abc={abc!r}'&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;string&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'test'&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;center&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'*'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;string&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'***test***'&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="mi"&gt;10&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Nested formatting
&lt;/h2&gt;

&lt;p&gt;Since we can sometimes have rather complicated format specifications, like &lt;code&gt;~^30s&lt;/code&gt; or &lt;code&gt;0&amp;gt;12,.2f&lt;/code&gt;, it makes sense to be able to extract those out into variables as well. And that's exactly what &lt;strong&gt;nested formatting&lt;/strong&gt; lets us do.&lt;/p&gt;

&lt;p&gt;Some things that you can do with &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Variable length padding
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;string&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'Python'&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="si"&gt;}}&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;~~~~~~~&lt;/span&gt;&lt;span class="n"&gt;Python&lt;/span&gt;&lt;span class="o"&gt;~~~~~~~&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;putting in the format spec as a variable, or as multiple variables:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;math&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;pi&lt;/span&gt;

&lt;span class="n"&gt;digits&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'Enter number of digits of pi: '&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="n"&gt;length&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'Enter string length: '&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="n"&gt;alignment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'Enter alignment (&amp;lt;, &amp;gt; or ^): '&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;padding_char&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'Enter padding character: '&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;pi&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;padding_char&lt;/span&gt;&lt;span class="si"&gt;}{&lt;/span&gt;&lt;span class="n"&gt;alignment&lt;/span&gt;&lt;span class="si"&gt;}{&lt;/span&gt;&lt;span class="n"&gt;length&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;digits&lt;/span&gt;&lt;span class="si"&gt;}}&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;Enter number of digits of pi: 8   
Enter string length: 30
&lt;/span&gt;&lt;span class="gp"&gt;Enter alignment (&amp;lt;, &amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;or ^&lt;span class="o"&gt;)&lt;/span&gt;: ^
&lt;span class="go"&gt;Enter padding character: _
__________3.1415927___________
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Custom formatting using &lt;code&gt;__format__&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;You can define custom format handling in your own objects by overriding the &lt;code&gt;__format__&lt;/code&gt; method on the formatter object. This allows you to define (mostly) arbitrary formatting semantics.&lt;/p&gt;

&lt;p&gt;Here's an example, with more sensible names for datetime formatting:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;datetime&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BetterDatetime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;substitutions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="s"&gt;'%day'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;'%A'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;'%date'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;'%d'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;'%monthname'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;'%B'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;'%month'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;'%m'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;'%year'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;'%Y'&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__format__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;format_spec&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;replacement&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;substitutions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
            &lt;span class="n"&gt;format_spec&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;format_spec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;replacement&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;super&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;__format__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;format_spec&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s"&gt;'Today is &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;BetterDatetime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;day&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;date&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;monthname&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;year&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Output: Today is Monday, 8 July 2021
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Limitations
&lt;/h2&gt;

&lt;p&gt;As amazing as f-strings are, they're not the be-all and end-all of string formatting in Python. &lt;em&gt;(but they come very close!)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Some nitpicks from my side about f-strings are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;You can't separate the string template from the data being embedded. In str.format, you can store the strings themselves as templates in a separate file, like &lt;code&gt;text = '{user} has left'&lt;/code&gt;. Then, you can import &lt;code&gt;text&lt;/code&gt; and use &lt;code&gt;text.format(user=...)&lt;/code&gt;. You can't do this with f-strings.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;f-strings only work in Python 3.6+, and &lt;code&gt;{x=}&lt;/code&gt; syntax only works in Python 3.8+&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;There's also no real replacement for the &lt;code&gt;str.format_map&lt;/code&gt; method using f-strings.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;All in all, f-strings are awesome, and everyone should use them :P&lt;/p&gt;

&lt;p&gt;Anywho, if you have any questions or suggestions, drop them below. I'd love to hear from you ✨&lt;/p&gt;

</description>
      <category>python</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Ace your LeetCode preparations</title>
      <dc:creator>Tushar Sadhwani</dc:creator>
      <pubDate>Mon, 24 May 2021 12:14:56 +0000</pubDate>
      <link>https://forem.com/tusharsadhwani/ace-your-leetcode-preparations-40l</link>
      <guid>https://forem.com/tusharsadhwani/ace-your-leetcode-preparations-40l</guid>
      <description>&lt;p&gt;I've been practicing my Data Structures and Algorithms on LeetCode for a few months now, and it's an awesome platform. The quality of the questions is generally great, there's very nice explanations for most of the solutions, and there's a very motivated and active community around all of it. Overall, &lt;strong&gt;LeetCode is a great platform.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;BUT, I had two slight problems with it:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;I personally never understood the idea of writing your code and testing it on a web editor. I mean, I have my own programming environment tailored to exactly how I like to write and test my code. And yes, granted that I'll have to use a google doc or something for my interviews, but I still prefer to have control over how I practice.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;I'd like to keep and test my solutions locally, in a version-controlled manner, so that I can come back to them later, search through them easily, make changes over time, and to just make sure I never lose my code.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;So for this, I created my own LeetCode workflow and local testing library:&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://github.com/tusharsadhwani/python_leetcode_runner" rel="noopener noreferrer"&gt;python-leetcode-runner&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjc0e155cb0c46j4vs736.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjc0e155cb0c46j4vs736.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And it has made me many times more productive in solving leetcode problems.&lt;/p&gt;

&lt;h2&gt;
  
  
  An example workflow
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;I start with opening my github repo where I store all of my leetcode problems: &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0ekjb1stgjvd4u5thl3i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0ekjb1stgjvd4u5thl3i.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Then I head over to any leetcode problem page (example: &lt;a href="https://leetcode.com/problems/plus-one/" rel="noopener noreferrer"&gt;Plus One&lt;/a&gt;). I copy the problem title and format it to be used as my file name (I specifically created the &lt;a href="https://github.com/tusharsadhwani/snekify" rel="noopener noreferrer"&gt;snekify&lt;/a&gt; cli tool for that), and then copy over the Solution code snippet.&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg7xrybu53nwgqgpyicwi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg7xrybu53nwgqgpyicwi.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;
This creates the filename I want.

 

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fppcrdakrnpoq4aojeovj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fppcrdakrnpoq4aojeovj.png" alt="image"&gt;&lt;/a&gt;I also use static type checking, but feel free to remove that! &lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Then I copy over the given example test cases into a variable called &lt;code&gt;tests&lt;/code&gt;:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqm7pahnnorj770nzctfu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqm7pahnnorj770nzctfu.png" alt="image"&gt;&lt;/a&gt; &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F582b21d0z9a54p4faare.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F582b21d0z9a54p4faare.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Then it's time to write a solution and test it using the &lt;code&gt;pyleet&lt;/code&gt; command given by my testing library: &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0z3g5tsc73x5fzrxb9at.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0z3g5tsc73x5fzrxb9at.png" alt="image"&gt;&lt;/a&gt; &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fys4g5eg77ib2thkfc33d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fys4g5eg77ib2thkfc33d.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Uh oh. Looks like I missed an edge case. Let's fix the code: &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg1thm3azff0w7cnsherp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg1thm3azff0w7cnsherp.png" alt="image"&gt;&lt;/a&gt; &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fovyi625a9wyf9f43189n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fovyi625a9wyf9f43189n.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And now all tests pass. Now you can copy your code file (yes, with the &lt;code&gt;tests&lt;/code&gt; and all) straight into leetcode's editor and submit it. No more silly "Wrong Answers".&lt;/p&gt;

&lt;h2&gt;
  
  
  Advanced use cases
&lt;/h2&gt;

&lt;p&gt;Another example: &lt;a href="https://leetcode.com/problems/linked-list-cycle/" rel="noopener noreferrer"&gt;Linked List cycle&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now this has an issue: We need to transform the given input into the linked list data structure, before running our solution.&lt;/p&gt;

&lt;p&gt;In other questions for example, you don't just have to match expected output with function output. Like sometimes it might ask you to modify a list in-place, or some might have answers where the order of the output doesn't matter, etc.&lt;/p&gt;

&lt;p&gt;For that case, you can provide your own &lt;strong&gt;custom validator function&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;A &lt;code&gt;validator&lt;/code&gt; is a function that receives 3 arguments:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;method&lt;/code&gt;: your leetcode solution function&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;inputs&lt;/code&gt;: your test inputs tuple&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;expected&lt;/code&gt;: your expected test output value&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Validator solution example
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Head to &lt;a href="https://leetcode.com/problems/linked-list-cycle/" rel="noopener noreferrer"&gt;the question&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Copy the problem title, format it, and paste the sample code and examples.
&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0q77wea4f4f293gcdg2q.png" alt="image"&gt; &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fozbqxvspqwhjsuc7x4gw.png" alt="image"&gt; &lt;/li&gt;
&lt;li&gt;Now to be able to run the tests locally, we need to write our own code to convert the array into a linked list: &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcs5i3k298is70mq30b3z.png" alt="image"&gt;
&lt;/li&gt;
&lt;li&gt;Now we can solve the question: &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhmhyiymwdgvo9xxl5irx.png" alt="image"&gt;
&lt;/li&gt;
&lt;li&gt;Running the tests: &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvm0wg2di5w4thu882y47.png" alt="image"&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And sure enough, we passed all the test cases. Now simply copy the entire code over to leetcode, and:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fznhwcxolq6ctgh53f0f1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fznhwcxolq6ctgh53f0f1.png" alt="image"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;You can find the complete solution &lt;a href="https://github.com/tusharsadhwani/leetcode/blob/master/linked_list_cycle_alt.py" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Extra tips
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;I use &lt;a href="https://mypy-lang.org" rel="noopener noreferrer"&gt;mypy&lt;/a&gt; to run static type checking on my code, which ensures stuff like &lt;strong&gt;no runtime Null Pointer Exceptions&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;I've created a bunch of &lt;strong&gt;code snippets&lt;/strong&gt; that auto-fill the test cases, the validator function, and the assert statements. These snippets can be used in VSCode as of now. More info on the &lt;a href="https://github.com/tusharsadhwani/python_leetcode_runner" rel="noopener noreferrer"&gt;github page&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;My solutions to all of the problems are stored in this &lt;a href="https://github.com/tusharsadhwani/leetcode" rel="noopener noreferrer"&gt;github repository&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Footnotes
&lt;/h2&gt;

&lt;p&gt;Currently this package only works with Python solutions. But if required, it can be extended to use any language at all. If you're interested in working on other language support, do let me know.&lt;/p&gt;

&lt;p&gt;Thanks for reading, I hope this helps you be more productive. ✨&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>tooling</category>
      <category>python</category>
    </item>
    <item>
      <title>I fixed Google's scripting tool</title>
      <dc:creator>Tushar Sadhwani</dc:creator>
      <pubDate>Sat, 08 May 2021 14:45:53 +0000</pubDate>
      <link>https://forem.com/tusharsadhwani/i-fixed-google-s-scripting-tool-13op</link>
      <guid>https://forem.com/tusharsadhwani/i-fixed-google-s-scripting-tool-13op</guid>
      <description>&lt;p&gt;So someone at Google released a tool called &lt;a href="https://github.com/google/zx"&gt;zx&lt;/a&gt; a couple days ago, and...&lt;/p&gt;

&lt;p&gt;Well, take a look at it for yourself:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--lUMjd0_7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xq4cg6xtc7881cydwi2z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--lUMjd0_7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xq4cg6xtc7881cydwi2z.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I can't be the only one who doesn't like: &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;The idea of having to install nodejs and npm on my servers just to run a shell script.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The &lt;code&gt;await $&lt;/code&gt; syntax used for every. single. command.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;And I thought I could do better, so I tried. And this is what I came up with:&lt;/p&gt;

&lt;h2&gt;
  
  
  Introducing zxpy
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;#! /usr/bin/env zxpy
&lt;/span&gt;&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="s"&gt;'echo Hello world!'&lt;/span&gt;

&lt;span class="n"&gt;file_count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="s"&gt;'ls -1 | wc -l'&lt;/span&gt;
&lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"file count is:"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;file_count&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It fixes the two problems I had in the following ways:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;It uses Python instead. Not only is Python a much more popular choice for scripting on desktop, it is also pre-installed on a lot more systems. Most linux and MacOS desktops, and arch/ubuntu based linux servers ship with it installed (probably many others do as well!)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It uses a simple &lt;code&gt;~'shell command'&lt;/code&gt; syntax. It's synchronous by default, but in my experience, most shell scripts are as well. It is possible to add async support, and if needed I'll add it in the future, but synchronous as default seems a lot more sane to me. :)&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;So, why not give it a try?&lt;/p&gt;

&lt;p&gt;It's available on &lt;a href="https://pypi.org/project/zxpy"&gt;pip&lt;/a&gt;, and the source code, along with a few examples, is available &lt;a href="https://github.com/tusharsadhwani/zxpy"&gt;on GitHub&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>showdev</category>
      <category>python</category>
      <category>bash</category>
    </item>
    <item>
      <title>The Comprehensive Guide to mypy</title>
      <dc:creator>Tushar Sadhwani</dc:creator>
      <pubDate>Wed, 05 May 2021 22:04:17 +0000</pubDate>
      <link>https://forem.com/tusharsadhwani/the-comprehensive-guide-to-mypy-561m</link>
      <guid>https://forem.com/tusharsadhwani/the-comprehensive-guide-to-mypy-561m</guid>
      <description>&lt;blockquote&gt;
&lt;h3&gt;
  
  
  Read the original on my &lt;a href="https://sadh.life/post/mypy-guide" rel="noopener noreferrer"&gt;personal blog&lt;/a&gt;
&lt;/h3&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://github.com/python/mypy" rel="noopener noreferrer"&gt;Mypy&lt;/a&gt; is a &lt;strong&gt;static type checker&lt;/strong&gt; for Python. It acts as a linter, that allows you to write statically typed code, and verify the soundness of your types.&lt;/p&gt;

&lt;p&gt;All mypy does is check your type hints. It's &lt;strong&gt;not like TypeScript&lt;/strong&gt;, which needs to be compiled before it can work. &lt;strong&gt;All mypy code is valid Python, no compiler needed&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This gives us the advantage of having types, as you can know for certain that there is no type-mismatch in your code, just as you can in typed, compiled languages like C++ and Java, but you also get the benefit of being Python 🐍✨ &lt;em&gt;(you also get other benefits like null safety!)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;For a more detailed explanation on what are types useful for, head over to the blog I wrote previously: &lt;a href="https://dev.to/tusharsadhwani/does-python-need-types-59if"&gt;Does Python need types?&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This article is going to be a deep dive for anyone who wants to learn about mypy, and all of its capabilities.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;If you haven't noticed the article length, this is going to be long. So grab a cup of your favorite beverage, and let's get straight into it.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;
  
  
  Index
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;
Setting up mypy

&lt;ul&gt;
&lt;li&gt;Using mypy in the terminal&lt;/li&gt;
&lt;li&gt;Using mypy in VSCode&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Primitive types&lt;/li&gt;

&lt;li&gt;Collection types&lt;/li&gt;

&lt;li&gt;Type debugging - Part 1&lt;/li&gt;

&lt;li&gt;Union and Optional&lt;/li&gt;

&lt;li&gt;Any type&lt;/li&gt;

&lt;li&gt;

Miscellaneous types

&lt;ul&gt;
&lt;li&gt;Tuple&lt;/li&gt;
&lt;li&gt;TypedDict&lt;/li&gt;
&lt;li&gt;Literal&lt;/li&gt;
&lt;li&gt;Final&lt;/li&gt;
&lt;li&gt;NoReturn&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Typing classes&lt;/li&gt;

&lt;li&gt;Typing namedtuples&lt;/li&gt;

&lt;li&gt;Typing decorators&lt;/li&gt;

&lt;li&gt;Typing generators&lt;/li&gt;

&lt;li&gt;Typing &lt;code&gt;*args&lt;/code&gt; and &lt;code&gt;**kwargs&lt;/code&gt;
&lt;/li&gt;

&lt;li&gt;Duck types&lt;/li&gt;

&lt;li&gt;Function overloading with &lt;code&gt;@overload&lt;/code&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;code&gt;Type&lt;/code&gt; type&lt;/li&gt;

&lt;li&gt;Typing pre-existing projects&lt;/li&gt;

&lt;li&gt;Type debugging - Part 2&lt;/li&gt;

&lt;li&gt;Typing context managers&lt;/li&gt;

&lt;li&gt;Typing async functions&lt;/li&gt;

&lt;li&gt;

Making your own Generics

&lt;ul&gt;
&lt;li&gt;Generic functions&lt;/li&gt;
&lt;li&gt;Generic classes&lt;/li&gt;
&lt;li&gt;Generic types&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Advanced/Recursive type checking with &lt;code&gt;Protocol&lt;/code&gt;
&lt;/li&gt;

&lt;li&gt;Further learning&lt;/li&gt;

&lt;/ul&gt;

&lt;h1&gt;
  
  
  Setting up mypy
&lt;/h1&gt;

&lt;p&gt;All you really need to do to set it up is &lt;code&gt;pip install mypy&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using mypy in the terminal
&lt;/h2&gt;

&lt;p&gt;Let's create a regular python file, and call it &lt;code&gt;test.py&lt;/code&gt;:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;This doesn't have any type definitions yet, but let's run mypy over it to see what it says.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

$ mypy test.py
Success: no issues found in 1 source file


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;🤨&lt;/p&gt;

&lt;p&gt;Don't worry though, it's nothing unexpected. As explained in &lt;a href="https://dev.to/tusharsadhwani/does-python-need-types-59if"&gt;my previous article&lt;/a&gt;, &lt;strong&gt;mypy doesn't force you to add types to your code&lt;/strong&gt;. But, if it finds types, it will evaluate them.&lt;/p&gt;

&lt;p&gt;This can definitely lead to mypy missing entire parts of your code just because you accidentally forgot to add types.&lt;/p&gt;

&lt;p&gt;Thankfully, there's ways to customise mypy to tell it to always check for stuff:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;

&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;mypy &lt;span class="nt"&gt;--disallow-untyped-defs&lt;/span&gt; test.py
&lt;span class="go"&gt;test.py:1: error: Function is missing a return type annotation
Found 1 error in 1 file (checked 1 source file)


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;And now it gave us the error we wanted.&lt;/p&gt;

&lt;p&gt;There are a lot of these &lt;code&gt;--disallow-&lt;/code&gt; arguments that we should be using if we are starting a new project to prevent such mishaps, but mypy gives us an extra powerful one that does it all: &lt;code&gt;--strict&lt;/code&gt;&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;

&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;mypy &lt;span class="nt"&gt;--strict&lt;/span&gt; test.py               
&lt;span class="go"&gt;test.py:1: error: Function is missing a return type annotation
test.py:4: error: Call to untyped function "give_number" in typed context
Found 2 errors in 1 file (checked 1 source file)


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
The actual mypy output is all nice and colourful



&lt;p&gt;This gave us even more information: the fact that we're using &lt;code&gt;give_number&lt;/code&gt; in our code, which doesn't have a defined return type, so that piece of code also can have unintended issues.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt;: for starters, use &lt;code&gt;mypy --strict filename.py&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  Using mypy in VSCode
&lt;/h2&gt;

&lt;p&gt;VSCode has pretty good integration with mypy. All you need to get mypy working with it is to add this to your &lt;code&gt;settings.json&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"python.linting.mypyEnabled"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"python.linting.mypyArgs"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"--ignore-missing-imports"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"--follow-imports=silent"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"--show-column-numbers"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"--strict"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Now opening your code folder in python should show you the exact same errors in the "Problems" pane:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7d9go5wksy1ot63f8ib4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7d9go5wksy1ot63f8ib4.png" alt="VSCode Problems pane showing the same errors"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Also, if you're using VSCode I'll highly suggest installing &lt;a href="https://marketplace.visualstudio.com/items?itemName=ms-python.vscode-pylance" rel="noopener noreferrer"&gt;Pylance&lt;/a&gt; from the Extensions panel, it'll help a lot with tab-completion and getting better insight into your types.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Okay, now on to actually fixing these issues.&lt;/p&gt;
&lt;h1&gt;
  
  
  Primitive types
&lt;/h1&gt;

&lt;p&gt;The most fundamental types that exist in mypy are the primitive types. To name a few:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;int&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;str&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;float&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;bool&lt;/code&gt;
...&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Notice a pattern?&lt;/p&gt;

&lt;p&gt;Yup. These are the same exact primitive Python data types that you're familiar with.&lt;/p&gt;

&lt;p&gt;And these are actually all we need to fix our errors:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;All we've changed is the function's definition in &lt;code&gt;def&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqvdyekz839662s6krh01.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqvdyekz839662s6krh01.png" alt="The code's diff"&gt;&lt;/a&gt;&lt;/p&gt;
Notice the highlighted part



&lt;p&gt;What this says is "function &lt;code&gt;double&lt;/code&gt; takes an argument &lt;code&gt;n&lt;/code&gt; which is an &lt;code&gt;int&lt;/code&gt;, and the function returns an &lt;code&gt;int&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;And running mypy now:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;

&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;mypy &lt;span class="nt"&gt;--strict&lt;/span&gt; test.py
&lt;span class="go"&gt;Success: no issues found in 1 source file


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.fluffy.cc%2FMKjDMmwXxZlqRTwnn070gVqZ8Rwh6d3p.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.fluffy.cc%2FMKjDMmwXxZlqRTwnn070gVqZ8Rwh6d3p.gif" alt="Ship it!"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Congratulations, you've just written your first type-checked Python program 🎉&lt;/p&gt;

&lt;p&gt;We can run the code to verify that it indeed, does work:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;

&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;python test.py
&lt;span class="go"&gt;42


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;I should clarify, that mypy does all of its type checking without ever running the code. It is what's called a &lt;strong&gt;static analysis tool&lt;/strong&gt; (this static is different from the static in "static typing"), and essentially what it means is that it works not by running your python code, but by &lt;strong&gt;evaluating your program's structure&lt;/strong&gt;. What this means is, if your program does interesting things like making API calls, or deleting files on your system, you can still run mypy over your files and it will have no real-world effect.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;What is interesting to note, is that we have declared &lt;code&gt;num&lt;/code&gt; in the program as well, but we never told mypy what type it is going to be, and yet it still worked just fine.&lt;/p&gt;

&lt;p&gt;We could tell mypy what type it is, like so:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;And mypy would be equally happy with this as well. But we don't have to provide this type, because mypy knows its type already. Because &lt;code&gt;double&lt;/code&gt; is only supposed to return an &lt;code&gt;int&lt;/code&gt;, &lt;strong&gt;mypy inferred it&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fenz740p3lztmic7c7us4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fenz740p3lztmic7c7us4.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;
Basic inference actually works without Pylance too.



&lt;p&gt;And &lt;em&gt;inference is cool&lt;/em&gt;. For 80% of the cases, you'll only be writing types for function and method definitions, as we did in the first example. One notable exception to this is "empty collection types", which we will discuss now.&lt;/p&gt;

&lt;h1&gt;
  
  
  Collection types
&lt;/h1&gt;

&lt;p&gt;Collection types are how you're able to add types to collections, such as "a list of strings", or "a dictionary with string keys and boolean values", and so on.&lt;/p&gt;

&lt;p&gt;Some collection types include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;List&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Dict&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Set&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;DefaultDict&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Deque&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Counter&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now these might sound very familiar, &lt;strong&gt;these aren't the same as the builtin collection types&lt;/strong&gt; (more on that later).&lt;/p&gt;

&lt;p&gt;These are all defined in the &lt;code&gt;typing&lt;/code&gt; module that comes built-in with Python, and there's one thing that all of these have in common: they're &lt;em&gt;generic&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;I have an entire section dedicated to generics below, but what it boils down to is that "with generic types, you can pass types inside other types". Here's how you'd use collection types:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;This tells mypy that &lt;code&gt;nums&lt;/code&gt; should be a list of integers (&lt;code&gt;List[int]&lt;/code&gt;), and that &lt;code&gt;average&lt;/code&gt; returns a &lt;code&gt;float&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Here's a couple more examples:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Remember when I said that empty collections is one of the rare cases that need to be typed? This is because there's no way for mypy to infer the types in that case:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Since the set has no items to begin with, mypy can't statically infer what type it should be.&lt;/p&gt;

&lt;p&gt;
  PS:
  &lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Small note, if you try to run mypy on the piece of code above, it'll actually succeed. It's because the mypy devs are smart, and they added simple cases of look-ahead inference. Meaning, new versions of mypy can figure out such types in simple cases. Keep in mind that it doesn't always work.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;/p&gt;



&lt;p&gt;To fix this, you can manually add in the required type:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: Starting from Python 3.7, you can add a future import, &lt;code&gt;from __future__ import annotations&lt;/code&gt; at the top of your files, which will allow you to use the builtin types as generics, i.e. you can use &lt;code&gt;list[int]&lt;/code&gt; instead of &lt;code&gt;List[int]&lt;/code&gt;. If you're using Python 3.9 or above, you can use this syntax without needing the &lt;code&gt;__future__&lt;/code&gt; import at all. However, there are some edge cases where it might not work, so in the meantime I'll suggest using the &lt;code&gt;typing.List&lt;/code&gt; variants. This is detailed in &lt;a href="https://www.python.org/dev/peps/pep-0585/" rel="noopener noreferrer"&gt;PEP 585&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;
  
  
  Type debugging - Part 1
&lt;/h1&gt;

&lt;p&gt;Let's say you're reading someone else's — or your own past self's — code, and it's not really apparent what the type of a variable is. The code is using a lot of inference, and it's using some builtin methods that you don't exactly remember how they work, bla bla.&lt;/p&gt;

&lt;p&gt;Thankfully mypy lets you reveal the type of any variable by using &lt;code&gt;reveal_type&lt;/code&gt;:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Running mypy on this piece of code gives us:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;

&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;mypy &lt;span class="nt"&gt;--strict&lt;/span&gt; test.py 
&lt;span class="go"&gt;test.py:12: note: Revealed type is 'builtins.int'


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Ignore the builtins for now, it's able to tell us that &lt;code&gt;counts&lt;/code&gt; here is an &lt;code&gt;int&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Cool, right? You don't need to rely on an IDE or VSCode, to use hover to check the types of a variable. A simple terminal and mypy is all you need. &lt;em&gt;(although VSCode internally uses a similar process to this to get all type informations)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;However, some of you might be wondering where &lt;code&gt;reveal_type&lt;/code&gt; came from. We didn't import it from &lt;code&gt;typing&lt;/code&gt;... is it a new builtin? Is that even valid in python?&lt;/p&gt;

&lt;p&gt;And sure enough, if you try to run the code:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;

py test.py    
Traceback (most recent call last):
&lt;/span&gt;&lt;span class="gp"&gt;  File "/home/tushar/code/test/test.py", line 12, in &amp;lt;module&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="go"&gt;    reveal_type(counts)
NameError: name 'reveal_type' is not defined


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;&lt;code&gt;reveal_type&lt;/code&gt; is a special "mypy function". Since python doesn't know about types (type annotations are ignored at runtime), only mypy knows about the types of variables when it runs its type checking. So, only mypy can work with &lt;code&gt;reveal_type&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;All this means, is that &lt;strong&gt;you should only use &lt;code&gt;reveal_type&lt;/code&gt; to debug your code, and remove it when you're done debugging&lt;/strong&gt;.&lt;/p&gt;
&lt;h1&gt;
  
  
  Union and Optional
&lt;/h1&gt;

&lt;p&gt;So far, we have only seen variables and collections that can hold only one type of value. But what about this piece of code?&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;What's the type of &lt;code&gt;fav_color&lt;/code&gt; in this code?&lt;/p&gt;

&lt;p&gt;Let's try to do a &lt;code&gt;reveal_type&lt;/code&gt;:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;BTW, since this function has no return statement, its return type is &lt;code&gt;None&lt;/code&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Running mypy on this:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;

&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;mypy test.py 
&lt;span class="go"&gt;test.py:5: note: Revealed type is 'Union[builtins.str*, None]'


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;And we get one of our two new types: &lt;em&gt;Union&lt;/em&gt;. Specifically, &lt;code&gt;Union[str, None]&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;All this means, is that &lt;code&gt;fav_color&lt;/code&gt; can be one of two different types, &lt;strong&gt;either &lt;code&gt;str&lt;/code&gt;, or &lt;code&gt;None&lt;/code&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;And unions are actually very important for Python, because of how Python does polymorphism. Here's a simpler example:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;

&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;python test.py
&lt;span class="go"&gt;Hi!
This is a test
of polymorphism


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Now let's add types to it, and learn some things by using our friend &lt;code&gt;reveal_type&lt;/code&gt;:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;Can you guess the output of the &lt;code&gt;reveal_type&lt;/code&gt;s?&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;

&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;mypy test.py 
&lt;span class="go"&gt;test.py:4: note: Revealed type is 'Union[builtins.str, builtins.list[builtins.str]]'
test.py:8: note: Revealed type is 'builtins.list[builtins.str]'
test.py:11: note: Revealed type is 'builtins.str'


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Mypy is smart enough, where if you add an &lt;code&gt;isinstance(...)&lt;/code&gt; check to a variable, it will correctly assume that the type inside that block is &lt;em&gt;narrowed to that type.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In our case, &lt;code&gt;item&lt;/code&gt; was correctly identified as &lt;code&gt;List[str]&lt;/code&gt; inside the &lt;code&gt;isinstance&lt;/code&gt; block, and &lt;code&gt;str&lt;/code&gt; in the &lt;code&gt;else&lt;/code&gt; block.&lt;/p&gt;

&lt;p&gt;This is an extremely powerful feature of mypy, called &lt;strong&gt;Type narrowing&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Now, here's a more contrived example, a tpye-annotated Python implementation of the builtin function &lt;code&gt;abs&lt;/code&gt;:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;And that's everything you need to know about Union.&lt;/p&gt;

&lt;p&gt;... so what's &lt;code&gt;Optional&lt;/code&gt; you ask?&lt;/p&gt;

&lt;p&gt;Well, &lt;code&gt;Union[X, None]&lt;/code&gt; seemed to occur so commonly in Python, that they decided it needs a shorthand. &lt;code&gt;Optional[str]&lt;/code&gt; is just a shorter way to write &lt;code&gt;Union[str, None]&lt;/code&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  Any type
&lt;/h1&gt;

&lt;p&gt;If you ever try to run &lt;code&gt;reveal_type&lt;/code&gt; inside an untyped function, this is what happens:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;

&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;mypy test.py         
&lt;span class="go"&gt;test.py:6: note: Revealed type is 'Any'
test.py:6: note: 'reveal_type' always outputs 'Any' in unchecked functions


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
Didn't use --strict, or it'd throw errors


&lt;p&gt;The revealed type is told to be &lt;code&gt;Any&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Any&lt;/code&gt; just means that &lt;em&gt;anything can be passed here&lt;/em&gt;. Whatever is passed, mypy should just accept it. In other words, &lt;strong&gt;&lt;code&gt;Any&lt;/code&gt; turns off type checking&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Of course, this means that &lt;em&gt;if you want to take advantage of mypy, you should avoid using &lt;code&gt;Any&lt;/code&gt; as much as you can&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;But since Python is inherently a dynamically typed language, in some cases it's impossible for you to know what the type of something is going to be. For such cases, you can use &lt;code&gt;Any&lt;/code&gt;. For example:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;You can also use &lt;code&gt;Any&lt;/code&gt; as a placeholder value for something while you figure out what it should be, to make mypy happy in the meanwhile. But make sure to get rid of the &lt;code&gt;Any&lt;/code&gt; if you can .&lt;/p&gt;

&lt;h1&gt;
  
  
  Miscellaneous types
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Tuple
&lt;/h2&gt;

&lt;p&gt;You might think of tuples as an immutable list, but Python thinks of it in a very different way.&lt;/p&gt;

&lt;p&gt;Tuples are different from other collections, as they are essentially a way to represent a collection of data points related to an entity, kinda similar to how a C &lt;code&gt;struct&lt;/code&gt; is stored in memory. While other collections usually represent a bunch of objects, &lt;strong&gt;tuples usually represent a single object&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;A good example is sqlite:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Tuples also come in handy when you want to return multiple values from a function, for example:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Because of these reasons, tuples tend to have a fixed length, with each index having a specific type. (Our sqlite example had an array of length 3 and types &lt;code&gt;int&lt;/code&gt;, &lt;code&gt;str&lt;/code&gt; and &lt;code&gt;int&lt;/code&gt; respectively.&lt;/p&gt;

&lt;p&gt;Here's how you'd type a tuple:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;However, sometimes you do have to create variable length tuples. You can use the &lt;code&gt;Tuple[X, ...]&lt;/code&gt; syntax for that.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;...&lt;/code&gt; in this case simply means there's a variable number of elements in the array, but their type is &lt;code&gt;X&lt;/code&gt;. For example:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h2&gt;
  
  
  TypedDict
&lt;/h2&gt;

&lt;p&gt;A &lt;code&gt;TypedDict&lt;/code&gt; is a dictionary whose keys are always string, and values are of the specified type. At runtime, it behaves exactly like a normal dictionary.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;By default, all keys must be present in a &lt;code&gt;TypedDict&lt;/code&gt;. It is possible to override this by specifying &lt;code&gt;total=False&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Literal
&lt;/h2&gt;

&lt;p&gt;A &lt;code&gt;Literal&lt;/code&gt; represents the type of a literal value. You can use it to constrain already existing types like &lt;code&gt;str&lt;/code&gt; and &lt;code&gt;int&lt;/code&gt;, to just some specific values of them. Like so:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;

&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;mypy test.py 
&lt;span class="gp"&gt;test.py:7: error: Argument 1 to "i_only_take_5" has incompatible type "Literal[6]";&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;expected &lt;span class="s2"&gt;"Literal[5]"&lt;/span&gt;
&lt;span class="go"&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;This has some interesting use-cases. A notable one is to use it in place of simple enums:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;

&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;mypy test.py
&lt;span class="gp"&gt;test.py:8: error: Argument 1 to "make_request" has incompatible type "Literal['DLETE']";&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;expected &lt;span class="s2"&gt;"Union[Literal['GET'], Literal['POST'], Literal['DELETE']]"&lt;/span&gt;
&lt;span class="go"&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Oops, you made a typo in &lt;code&gt;'DELETE'&lt;/code&gt;! Don't worry, mypy saved you an hour of debugging.&lt;/p&gt;
&lt;h2&gt;
  
  
  Final
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;Final&lt;/code&gt; is an annotation that declares a variable as final. What that means that the variable cannot be re-assigned to. This is similar to &lt;code&gt;final&lt;/code&gt; in Java and &lt;code&gt;const&lt;/code&gt; in JavaScript.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;h2&gt;
  
  
  NoReturn
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;NoReturn&lt;/code&gt; is an interesting type. It's rarely ever used, but it still needs to exist, for that one time where you might have to use it.&lt;/p&gt;

&lt;p&gt;There are cases where you can have a function that might never return. Two possible reasons that I can think of for this are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The function always raises an exception, or&lt;/li&gt;
&lt;li&gt;The function is an infinite loop.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here's an example of both:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Note that in both these cases, typing the function as &lt;code&gt;-&amp;gt; None&lt;/code&gt; will also work. But if you intend for a function to never return anything, you should type it as &lt;code&gt;NoReturn&lt;/code&gt;, because then mypy will show an error if the function were to ever have a condition where it does return.&lt;/p&gt;

&lt;p&gt;For example, if you edit &lt;code&gt;while True:&lt;/code&gt; to be &lt;code&gt;while False:&lt;/code&gt; or &lt;code&gt;while some_condition()&lt;/code&gt; in the first example, mypy will throw an error:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;

&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;mypy test.py 
&lt;span class="go"&gt;test.py:6: error: Implicit return in function which does not return


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h1&gt;
  
  
  Typing classes
&lt;/h1&gt;

&lt;p&gt;All class methods are essentially typed just like regular functions, except for &lt;code&gt;self&lt;/code&gt;, which is left untyped. Here's a simple Stack class:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;If you've never seen the &lt;code&gt;{x!r}&lt;/code&gt; syntax inside f-strings, it's a way to use the &lt;code&gt;repr()&lt;/code&gt; of a value. For more information, &lt;a href="https://pyformat.info" rel="noopener noreferrer"&gt;pyformat.info&lt;/a&gt; is a very good resource for learning Python's string formatting features.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;There's however, one caveat to typing classes: You can't normally access the class itself inside the class' function declarations (because the class hasn't been finished declaring itself yet, because you're still declaring its methods).&lt;/p&gt;

&lt;p&gt;So something like this isn't valid Python:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;

&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;mypy &lt;span class="nt"&gt;--strict&lt;/span&gt; test.py
&lt;span class="go"&gt;Success: no issues found in 1 source file

&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;python test.py
&lt;span class="go"&gt;Traceback (most recent call last):
&lt;/span&gt;&lt;span class="gp"&gt;  File "/home/tushar/code/test/test.py", line 11, in &amp;lt;module&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="go"&gt;    class MyClass:
  File "/home/tushar/code/test/test.py", line 15, in MyClass
&lt;/span&gt;&lt;span class="gp"&gt;    def copy(self) -&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;MyClass:
&lt;span class="go"&gt;NameError: name 'MyClass' is not defined


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;There's two ways to fix this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Turn the classname into a string: The creators of PEP 484 and Mypy knew that such cases exist where you might need to define a return type which doesn't exist yet. So, mypy is able to check types if they're wrapped in strings.&lt;/li&gt;
&lt;/ul&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Use &lt;code&gt;from __future__ import annotations&lt;/code&gt;. What this does, is turn on a new feature in Python called "postponed evaluation of type annotations". This essentially makes Python treat all type annotations as strings, storing them in the internal &lt;code&gt;__annotations__&lt;/code&gt; attribute. Details are described in &lt;a href="https://www.python.org/dev/peps/pep-0563/" rel="noopener noreferrer"&gt;PEP 563&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;blockquote&gt;
&lt;p&gt;Starting with Python 3.11, the Postponed evaluation behaviour will become default, and you won't need to have the &lt;code&gt;__future__&lt;/code&gt; import anymore.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;
  
  
  Typing namedtuples
&lt;/h1&gt;

&lt;p&gt;&lt;code&gt;namedtuple&lt;/code&gt;s are a lot like tuples, except every index of their fields is named, and they have some syntactic sugar which allow you to access its properties like attributes on an object:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Since the underlying data structure is a tuple, and there's no real way to provide any type information to namedtuples, by default this will have a type of &lt;code&gt;Tuple[Any, Any, Any]&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;To combat this, Python has added a &lt;code&gt;NamedTuple&lt;/code&gt; class which you can extend to have the typed equivalent of the same:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;
  Inner workings of NamedTuple:
  &lt;p&gt;If you're curious how &lt;code&gt;NamedTuple&lt;/code&gt; works under the hood: &lt;code&gt;age: int&lt;/code&gt; is a &lt;strong&gt;type declaration&lt;/strong&gt;, without any assignment (like &lt;code&gt;age : int = 5&lt;/code&gt;). &lt;/p&gt;

&lt;p&gt;Type declarations inside a function or class don't actually define the variable, but they add the type annotation to that function or class' &lt;em&gt;metadata&lt;/em&gt;, in the form of a dictionary entry, into &lt;code&gt;x.__annotations__&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Doing &lt;code&gt;print(ishan.__annotations__)&lt;/code&gt; in the code above gives us &lt;code&gt;{'name': &amp;lt;class 'str'&amp;gt;, 'age': &amp;lt;class 'int'&amp;gt;, 'bio': &amp;lt;class 'str'&amp;gt;}&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;typing.NamedTuple&lt;/code&gt; uses these annotations to create the required tuple.&lt;/p&gt;

&lt;/p&gt;

&lt;h1&gt;
  
  
  Typing decorators
&lt;/h1&gt;

&lt;p&gt;Decorators are a fairly advanced, but really powerful feature of Python. If you don't know anything about decorators, I'd recommend you to watch &lt;a href="https://www.youtube.com/watch?v=WDMr6WolKUM" rel="noopener noreferrer"&gt;Anthony explains decorators&lt;/a&gt;, but I'll explain it in brief here as well.&lt;/p&gt;

&lt;p&gt;A decorator is essentially a function that wraps another function. Decorators can extend the functionalities of pre-existing functions, by running other side-effects whenever the original function is called. A decorator &lt;strong&gt;decorates a function by adding new functionality&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;A simple example would be to monitor how long a function takes to run:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;To be able to type this, we'd need a way to be able to define the type of a function. That way is called &lt;code&gt;Callable&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Callable&lt;/code&gt; is a generic type with the following syntax:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Callable[[&amp;lt;list of argument types&amp;gt;], &amp;lt;return type&amp;gt;]&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The types of a function's arguments goes into the first list inside &lt;code&gt;Callable&lt;/code&gt;, and the return type follows after. A few examples:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Here's how you'd implenent the previously-shown &lt;code&gt;time_it&lt;/code&gt; decorator:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;blockquote&gt;
&lt;p&gt;Note: &lt;code&gt;Callable&lt;/code&gt; is what's called a &lt;a href="https://devopedia.org/duck-typing" rel="noopener noreferrer"&gt;Duck Type&lt;/a&gt;. What it means, is that you can create your own custom object, and make it a valid &lt;code&gt;Callable&lt;/code&gt;, by implementing the magic method called &lt;code&gt;__call__&lt;/code&gt;. I have a dedicated section where I go in-depth about duck types ahead.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;
  
  
  Typing generators
&lt;/h1&gt;

&lt;p&gt;Generators are also a fairly advanced topic to completely cover in this article, and you can watch&lt;br&gt;
&lt;a href="https://www.youtube.com/watch?v=LjBa9sfJh7U" rel="noopener noreferrer"&gt;Anthony explains generators&lt;/a&gt;  if you've never heard of them. A brief explanation is this:&lt;/p&gt;

&lt;p&gt;Generators are a bit like perpetual functions. Instead of returning a value a single time, they &lt;code&gt;yield&lt;/code&gt; values out of them, which you can iterate over. When you &lt;code&gt;yield&lt;/code&gt; a value from an iterator, its execution pauses. But when another value is requested from the generator, it resumes execution from where it was last paused. When the generator function returns, the iterator stops.&lt;/p&gt;

&lt;p&gt;Here's an example:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;To add type annotations to generators, you need &lt;code&gt;typing.Generator&lt;/code&gt;. The syntax is as follows:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Generator[yield_type, throw_type, return_type]&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;With that knowledge, typing this is fairly straightforward:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Since we're not raising any errors in the generator, &lt;code&gt;throw_type&lt;/code&gt; is &lt;code&gt;None&lt;/code&gt;. And although the return type is &lt;code&gt;int&lt;/code&gt; which is correct, we're not really using the returned value anyway, so you could use &lt;code&gt;Generator[str, None, None]&lt;/code&gt; as well, and skip the &lt;code&gt;return&lt;/code&gt; part altogether.&lt;/p&gt;

&lt;h1&gt;
  
  
  Typing &lt;code&gt;*args&lt;/code&gt; and &lt;code&gt;**kwargs&lt;/code&gt; &lt;a&gt;
&lt;/a&gt;
&lt;/h1&gt;

&lt;p&gt;&lt;code&gt;*args&lt;/code&gt; and &lt;code&gt;**kwargs&lt;/code&gt; is a feature of python that lets you pass any number of arguments and keyword arguments to a function &lt;em&gt;(that's what the name &lt;code&gt;args&lt;/code&gt; and &lt;code&gt;kwargs&lt;/code&gt; stands for, but these names are just convention, you can name the variables anything)&lt;/em&gt;. &lt;a href="https://www.youtube.com/watch?v=CqafM-bsnW0" rel="noopener noreferrer"&gt;Anthony explains args and kwargs&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;All the extra arguments passed to &lt;code&gt;*args&lt;/code&gt; get turned into a tuple, and kewyord arguments turn into a dictionay, with the keys being the string keywords:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Since the &lt;code&gt;*args&lt;/code&gt; will always be of typle &lt;code&gt;Tuple[X]&lt;/code&gt;, and &lt;code&gt;**kwargs&lt;/code&gt; will always be of type &lt;code&gt;Dict[str, X]&lt;/code&gt;, we only need to provide one type value &lt;code&gt;X&lt;/code&gt; to type them. Here's a practical example:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h1&gt;
  
  
  Duck types
&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;Duck types&lt;/strong&gt; are a pretty fundamental concept of python: the entirety of the &lt;a href="https://docs.python.org/3/reference/datamodel.html" rel="noopener noreferrer"&gt;Python object model&lt;/a&gt; is built around the idea of duck types.&lt;/p&gt;

&lt;p&gt;Quoting Alex Martelli:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"You don't really care for IS-A -- you really only care for BEHAVES-LIKE-A-(in-this-specific-context), so, if you do test, this behaviour is what you should be testing for."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;What it means is that Python doesn't really care &lt;em&gt;what&lt;/em&gt; the type of an object is, but rather &lt;strong&gt;how does it behave&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;I had a short note above in typing decorators that mentioned duck typing a function with &lt;code&gt;__call__&lt;/code&gt;, now here's the actual implementation:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;
  PS.
  &lt;p&gt;&amp;gt; &lt;em&gt;Running mypy over the above code is going to give a cryptic error about "Special Forms", don't worry about that right now, we'll fix this in the Protocol section. All I'm showing right now is that the Python code works.&lt;/em&gt; &lt;/p&gt;

&lt;/p&gt;

&lt;p&gt;You can see that Python agrees that both of these  functions are "Call-able", i.e. you can call them using the &lt;code&gt;x()&lt;/code&gt; syntax. (this is why the type is called &lt;code&gt;Callable&lt;/code&gt;, and not something like &lt;code&gt;Function&lt;/code&gt;)&lt;/p&gt;

&lt;p&gt;What duck types provide you is to be able to define your function parameters and return types not in terms of &lt;em&gt;concrete classes&lt;/em&gt;, but in terms of &lt;em&gt;how your object behaves&lt;/em&gt;, giving you a lot more flexibility in what kinds of things you can utilize in your code now, and also allows much easier extensibility in the future without making "breaking changes".&lt;/p&gt;

&lt;p&gt;A simple example here:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Running this code with Python works just fine. But running mypy over this gives us the following error:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;

&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;mypy test.py 
&lt;span class="gp"&gt;test.py:12: error: Argument 1 to "count_non_empty_strings" has incompatible type "ValuesView[str]";&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;expected &lt;span class="s2"&gt;"List[str]"&lt;/span&gt;
&lt;span class="go"&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;&lt;code&gt;ValuesView&lt;/code&gt; is the type when you do &lt;code&gt;dict.values()&lt;/code&gt;, and although you could imagine it as a list of strings in this case, it's not exactly the type &lt;code&gt;List&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In fact, none of the other sequence types like &lt;code&gt;tuple&lt;/code&gt; or &lt;code&gt;set&lt;/code&gt; are going to work with this code. You could patch it for some of the builtin types by doing &lt;code&gt;strings: Union[List[str], Set[str], ...]&lt;/code&gt; and so on, but just how many types will you add? And what about third party/custom types?&lt;/p&gt;

&lt;p&gt;The correct solution here is to use a &lt;strong&gt;Duck Type&lt;/strong&gt; (yes, we finally got to the point). The only thing we want to ensure in this case is that the object can be iterated upon (which in Python terms means that it implements the &lt;code&gt;__iter__&lt;/code&gt; magic method), and the right type for that is &lt;code&gt;Iterable&lt;/code&gt;:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;And now mypy is happy with our code.&lt;/p&gt;

&lt;p&gt;There are many, &lt;em&gt;many&lt;/em&gt; of these duck types that ship within Python's &lt;code&gt;typing&lt;/code&gt; module, and a few of them include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Sequence&lt;/code&gt; for defining things that can be indexed and reversed, like &lt;code&gt;List&lt;/code&gt; and &lt;code&gt;Tuple&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;MutableMapping&lt;/code&gt;, for when you have a key-value pair kind-of data structure, like &lt;code&gt;dict&lt;/code&gt;, but also others like &lt;code&gt;defaultdict&lt;/code&gt;, &lt;code&gt;OrderedDict&lt;/code&gt; and &lt;code&gt;Counter&lt;/code&gt; from the collections module.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Collection&lt;/code&gt;, if all you care about is having a finite number of items in your data structure, eg. a &lt;code&gt;set&lt;/code&gt;, &lt;code&gt;list&lt;/code&gt;, &lt;code&gt;dict&lt;/code&gt;, or anything from the collections module.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;If you haven't already at this point, you should really look into how python's syntax and top level functions hook into Python's object model via &lt;code&gt;__magic_methods__&lt;/code&gt;, for essentially all of Python's behaviour. The documentation for it is &lt;a href="https://docs.python.org/3/reference/datamodel.html" rel="noopener noreferrer"&gt;right here&lt;/a&gt;, and there's an excellent &lt;a href="https://www.youtube.com/watch?v=7lmCu8wz8ro" rel="noopener noreferrer"&gt;talk by James Powell&lt;/a&gt; that really dives deep into this concept in the beginning.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;
  
  
  Function overloading with &lt;code&gt;@overload&lt;/code&gt; &lt;a&gt;
&lt;/a&gt;
&lt;/h1&gt;

&lt;p&gt;Let's write a simple &lt;code&gt;add&lt;/code&gt; function that supports &lt;code&gt;int&lt;/code&gt;'s and &lt;code&gt;float&lt;/code&gt;'s:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;The implementation seems perfectly fine... but mypy isn't happy with it:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;

&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;test.py:15: error: No overload variant of &lt;span class="s2"&gt;"__getitem__"&lt;/span&gt; of &lt;span class="s2"&gt;"list"&lt;/span&gt; matches argument &lt;span class="nb"&gt;type&lt;/span&gt; &lt;span class="s2"&gt;"float"&lt;/span&gt;
&lt;span class="go"&gt;test.py:15: note: Possible overload variants:
&lt;/span&gt;&lt;span class="gp"&gt;test.py:15: note:     def __getitem__(self, int) -&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;int
&lt;span class="gp"&gt;test.py:15: note:     def __getitem__(self, slice) -&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;List[int]
&lt;span class="go"&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;What mypy is trying to tell us here, is that in the line:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;print(joined_list[last_index])&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;last_index&lt;/code&gt; &lt;em&gt;could&lt;/em&gt; be of type &lt;code&gt;float&lt;/code&gt;. And checking with reveal_type, that definitely is the case:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffbiimqc22expxgmdgsks.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffbiimqc22expxgmdgsks.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And since it &lt;em&gt;could&lt;/em&gt;, mypy won't allow you to use a possible float value to index a list, because that will error out.&lt;/p&gt;

&lt;p&gt;One thing we could do is do an &lt;code&gt;isinstance&lt;/code&gt; assertion on our side to convince mypy:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;But this will be pretty cumbersome to do at every single place in our code where we use &lt;code&gt;add&lt;/code&gt; with &lt;code&gt;int&lt;/code&gt;'s. Also we as programmers &lt;em&gt;know&lt;/em&gt;, that passing two &lt;code&gt;int&lt;/code&gt;'s will only ever return an &lt;code&gt;int&lt;/code&gt;. But how do we tell mypy that?&lt;/p&gt;

&lt;p&gt;Answer: use &lt;code&gt;@overload&lt;/code&gt;. The syntax basically replicates what we wanted to say in the paragraph above:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;And now mypy knows that &lt;code&gt;add(3, 4)&lt;/code&gt; returns an &lt;code&gt;int&lt;/code&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note that Python has no way to ensure that the code actually always returns an &lt;code&gt;int&lt;/code&gt; when it gets &lt;code&gt;int&lt;/code&gt; values. It's your job as the programmer providing these overloads, to verify that they are correct. This is why in some cases, using &lt;code&gt;assert isinstance(...)&lt;/code&gt; could be better than doing this, but for most cases &lt;code&gt;@overload&lt;/code&gt; works fine.&lt;/p&gt;

&lt;p&gt;Also, in the overload definitions &lt;code&gt;-&amp;gt; int: ...&lt;/code&gt;, the &lt;code&gt;...&lt;/code&gt; at the end is a convention for when you provide &lt;a href="https://mypy.readthedocs.io/en/stable/stubs.html" rel="noopener noreferrer"&gt;type stubs&lt;/a&gt; for functions and classes, but you could technically write anything as the function body: &lt;code&gt;pass&lt;/code&gt;, &lt;code&gt;42&lt;/code&gt;, etc. It'll be ignored either way.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Another good overload example is this:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h1&gt;
  
  
  &lt;code&gt;Type&lt;/code&gt; type &lt;a&gt;
&lt;/a&gt;
&lt;/h1&gt;

&lt;p&gt;&lt;code&gt;Type&lt;/code&gt; is a type used to type classes. It derives from python's way of determining the type of an object at runtime:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;blockquote&gt;
&lt;p&gt;You'd usually use &lt;code&gt;issubclass(x, int)&lt;/code&gt; instead of &lt;code&gt;type(x) == int&lt;/code&gt; to check for behaviour, but sometimes knowing the exact type can help, for eg. in optimizations.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Since &lt;code&gt;type(x)&lt;/code&gt; returns the class of &lt;code&gt;x&lt;/code&gt;, the type of a class &lt;code&gt;C&lt;/code&gt; is &lt;code&gt;Type[C]&lt;/code&gt;:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;blockquote&gt;
&lt;p&gt;We had to use &lt;code&gt;Any&lt;/code&gt; in 3 places here, and 2 of them can be eliminated by using generics, and we'll talk about it later on.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;
  
  
  Typing pre-existing projects &lt;a&gt;
&lt;/a&gt;
&lt;/h1&gt;

&lt;p&gt;If you need it, mypy gives you the ability to add types to your project without ever modifying the original source code. It's done using what's called "stub files".&lt;/p&gt;

&lt;p&gt;Stub files are python-like files, that only contain &lt;strong&gt;type-checked variable, function, and class definitions&lt;/strong&gt;. It's kindof like a mypy &lt;em&gt;header file&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;You can make your own type stubs by creating a &lt;code&gt;.pyi&lt;/code&gt; file:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Now, run mypy on the current folder (make sure you have an &lt;code&gt;__init__.py&lt;/code&gt; file in the folder, if not, create an empty one).&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;

&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;ls&lt;/span&gt;
&lt;span class="go"&gt;__init__.py  test.py  test.pyi

&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;mypy &lt;span class="nt"&gt;--strict&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;span class="go"&gt;Success: no issues found in 2 source files


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h1&gt;
  
  
  Type debugging - Part 2
&lt;/h1&gt;

&lt;p&gt;Since we are on the topic of projects and folders, let's discuss another one of pitfalls that you can find yourselves in when using mypy.&lt;/p&gt;

&lt;p&gt;The first one is &lt;a href="https://www.python.org/dev/peps/pep-0420/" rel="noopener noreferrer"&gt;PEP 420&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A fact that took me some time to realise, was that &lt;strong&gt;for mypy to be able to type-check a folder, the folder must be a module&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Let's say you find yourself in this situatiion:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;

&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;tree
&lt;span class="c"&gt;.
&lt;/span&gt;&lt;span class="go"&gt;├── test.py
└── utils
    └── foo.py

1 directory, 2 files

&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;cat &lt;/span&gt;test.py               
&lt;span class="go"&gt;from utils.foo import average

print(average(3, 4))

&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;cat &lt;/span&gt;utils/foo.py 
&lt;span class="gp"&gt;def average(x: int, y: int) -&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;float:
&lt;span class="go"&gt;    return float(x + y) / 2

&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;py test.py      
&lt;span class="go"&gt;3.5

&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;mypy test.py 
&lt;span class="go"&gt;test.py:1: error: Cannot find implementation or library stub for module named 'utils.foo'
&lt;/span&gt;&lt;span class="gp"&gt;test.py:1: note: See https://mypy.readthedocs.io/en/latest/running_mypy.html#&lt;/span&gt;missing-imports
&lt;span class="go"&gt;Found 1 error in 1 file (checked 1 source file)


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;What's the problem? Python is able to find &lt;code&gt;utils.foo&lt;/code&gt; no problems, why can't mypy?&lt;/p&gt;

&lt;p&gt;The error is very cryptic, but the thing to focus on is the word "module" in the error. &lt;code&gt;utils.foo&lt;/code&gt; should be a module, and for that, the &lt;code&gt;utils&lt;/code&gt; folder should have an &lt;code&gt;__init__.py&lt;/code&gt;, even if it's empty.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;

&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;tree              
&lt;span class="c"&gt;.
&lt;/span&gt;&lt;span class="go"&gt;├── test.py
└── utils
    ├── foo.py
    └── __init__.py

1 directory, 3 files

&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;mypy test.py
&lt;span class="go"&gt;Success: no issues found in 1 source file


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Now, the same issue re-appears if you're installing your package via pip, because of a completely different reason:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;

&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;tree ..
&lt;span class="c"&gt;..
&lt;/span&gt;&lt;span class="go"&gt;├── setup.py
├── src
│   └── mypackage
│       ├── __init__.py
│       └── utils
│           ├── foo.py
│           └── __init__.py
└── test
    └── test.py

4 directories, 5 files

&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; ../setup.py
&lt;span class="go"&gt;from setuptools import setup, find_packages

setup(
    name="mypackage",
    packages = find_packages('src'),
    package_dir = {"":"src"}
)

&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;pip &lt;span class="nb"&gt;install&lt;/span&gt; ..
&lt;span class="go"&gt;[...]
successfully installed mypackage-0.0.0

&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;cat &lt;/span&gt;test.py
&lt;span class="go"&gt;from mypackage.utils.foo import average

print(average(3, 4))

&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;python test.py
&lt;span class="go"&gt;3.5

&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;mypy test.py
&lt;span class="go"&gt;test.py:1: error: Cannot find implementation or library stub for module named 'mypackage.utils.foo'
&lt;/span&gt;&lt;span class="gp"&gt;test.py:1: note: See https://mypy.readthedocs.io/en/latest/running_mypy.html#&lt;/span&gt;missing-imports
&lt;span class="go"&gt;Found 1 error in 1 file (checked 1 source file)


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;What now? Every folder has an &lt;code&gt;__init__.py&lt;/code&gt;, it's even installed as a pip package and the code runs, so we know that the module structure is right. What gives?&lt;/p&gt;

&lt;p&gt;Well, turns out that &lt;strong&gt;pip packages aren't type checked by mypy by default&lt;/strong&gt;. This behaviour exists because type definitions are opt-in by default. Python packages aren't expected to be type-checked, because mypy types are completely optional. If mypy were to assume every package has type hints, it would show possibly dozens of errors because a package doesn't have proper types, or used type hints for something else, etc.&lt;/p&gt;

&lt;p&gt;To opt-in for type checking your package, you need to add an empty &lt;code&gt;py.typed&lt;/code&gt; file into your package's root directory, and also include it as metadata in your &lt;code&gt;setup.py&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;

&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;tree ..
&lt;span class="c"&gt;..
&lt;/span&gt;&lt;span class="go"&gt;├── setup.py
├── src
│   └── mypackage
│       ├── __init__.py
│       ├── py.typed
│       └── utils
│           ├── foo.py
│           └── __init__.py
└── test
    └── test.py

4 directories, 6 files

&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; ../setup.py
&lt;span class="go"&gt;from setuptools import setup, find_packages

setup(
    name="mypackage",
    packages = find_packages(
        where = 'src',
    ),
    package_dir = {"":"src"},
    package_data={
        "mypackage": ["py.typed"],
    }
)

&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;mypy test.py
&lt;span class="go"&gt;Success: no issues found in 1 source file


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;There's yet another third pitfall that you might encounter sometimes, which is if &lt;code&gt;a.py&lt;/code&gt; declares a class &lt;code&gt;MyClass&lt;/code&gt;, and it imports stuff from a file &lt;code&gt;b.py&lt;/code&gt; which requires to import &lt;code&gt;MyClass&lt;/code&gt; from &lt;code&gt;a.py&lt;/code&gt; for type-checking purposes.&lt;/p&gt;

&lt;p&gt;This creates an import cycle, and Python gives you an &lt;code&gt;ImportError&lt;/code&gt;. To avoid this, simple add an &lt;code&gt;if typing.TYPE_CHECKING:&lt;/code&gt; block to the import statement in &lt;code&gt;b.py&lt;/code&gt;, since it only needs &lt;code&gt;MyClass&lt;/code&gt; for type checking. Also, everywhere you use &lt;code&gt;MyClass&lt;/code&gt;, add quotes: &lt;code&gt;'MyClass'&lt;/code&gt; so that Python is happy.&lt;/p&gt;
&lt;h1&gt;
  
  
  Typing Context managers
&lt;/h1&gt;

&lt;p&gt;Context managers are a way of adding common setup and teardown logic to parts of your code, things like opening and closing database connections, establishing a websocket, and so on. On the surface it might seem simple but it's a pretty extensive topic, and if you've never heard of it before, &lt;a href="https://www.youtube.com/watch?v=ExdtNMnP24I" rel="noopener noreferrer"&gt;Anthony covers it here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To define a context manager, you need to provide two magic methods in your class, namely &lt;code&gt;__enter__&lt;/code&gt; and &lt;code&gt;__exit__&lt;/code&gt;. They're then called automatically at the start and end if your &lt;code&gt;with&lt;/code&gt; block.&lt;/p&gt;

&lt;p&gt;You might have used a context manager before: &lt;code&gt;with open(filename) as file:&lt;/code&gt; - this uses a context manager underneath. Speaking of which, let's write our own implementation of &lt;code&gt;open&lt;/code&gt;:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;h1&gt;
  
  
  Typing async functions
&lt;/h1&gt;

&lt;p&gt;The &lt;code&gt;typing&lt;/code&gt; module has a duck type for all types that can be awaited: &lt;code&gt;Awaitable&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Just like how a regular function is a &lt;code&gt;Callable&lt;/code&gt;, an async function is a &lt;code&gt;Callable&lt;/code&gt; that returns an &lt;code&gt;Awaitable&lt;/code&gt;:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h1&gt;
  
  
  Generics &lt;a&gt;
&lt;/a&gt;
&lt;/h1&gt;

&lt;p&gt;Generics (or generic types) is a language feature that lets you "pass types inside other types".&lt;/p&gt;

&lt;p&gt;I personally think it is best explained with an example:&lt;/p&gt;

&lt;p&gt;Let's say you have a function that returns the first item in an array. To define this, we need this behaviour:&lt;/p&gt;

&lt;p&gt;"Given a list of type &lt;code&gt;List[X]&lt;/code&gt;, we will be returning an item of type &lt;code&gt;X&lt;/code&gt;."&lt;/p&gt;

&lt;p&gt;And that's exactly what generic types are: &lt;strong&gt;defining your return type based on the input type&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Generic functions
&lt;/h2&gt;

&lt;p&gt;We've seen &lt;code&gt;make_object&lt;/code&gt; from the Type type section before, but we had to use &lt;code&gt;Any&lt;/code&gt; to be able to support returning any kind of object that got created by calling &lt;code&gt;cls(*args)&lt;/code&gt;. But, we don't actually have to do that, because we can use generics. Here's how you'd do that:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;&lt;code&gt;T = TypeVar('T')&lt;/code&gt; is how you declare a generic type in Python. What the function definition now says, is "If i give you a class that makes &lt;code&gt;T&lt;/code&gt;'s, you'll be returning an object &lt;code&gt;T&lt;/code&gt;".&lt;/p&gt;

&lt;p&gt;And sure enough, the &lt;code&gt;reveal_type&lt;/code&gt; on the bottom shows that mypy knows &lt;code&gt;c&lt;/code&gt; is an object of &lt;code&gt;MyClass&lt;/code&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The generic type name &lt;code&gt;T&lt;/code&gt; is another convention, you can call it anything.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Another example: &lt;code&gt;largest&lt;/code&gt;, which returns the largest item in a list:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;This seems good, but mypy isn't happy:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;

&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;mypy &lt;span class="nt"&gt;--strict&lt;/span&gt; test.py
&lt;span class="gp"&gt;test.py:10: error: Unsupported left operand type for &amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"T"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="go"&gt;Found 1 error in 1 file (checked 1 source file)


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;This is because you need to ensure you can do &lt;code&gt;a &amp;lt; b&lt;/code&gt; on the objects, to compare them with each other, which isn't always the case:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

&amp;gt;&amp;gt;&amp;gt; {} &amp;lt; {}
Traceback (most recent call last):
  File "&amp;lt;stdin&amp;gt;", line 1, in &amp;lt;module&amp;gt;
TypeError: '&amp;lt;' not supported between instances of 'dict' and 'dict'


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;For this, we need a Duck Type that defines this "a less than b" behaviour.&lt;/p&gt;

&lt;p&gt;And although currently Python doesn't have one such builtin  hankfully, there's a "virtual module" that ships with mypy called &lt;code&gt;_typeshed&lt;/code&gt;. It has a lot of extra duck types, along with other mypy-specific features.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;Now, mypy will only allow passing lists of objects to this function that can be compared to each other.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you're wondering why checking for &lt;code&gt;&amp;lt;&lt;/code&gt; was enough while our code uses &lt;code&gt;&amp;gt;&lt;/code&gt;, &lt;a href="https://docs.python.org/3/reference/datamodel.html#object.__lt__" rel="noopener noreferrer"&gt;that's how python does comparisons&lt;/a&gt;. I'm planning to write an article on this later.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Note that &lt;code&gt;_typeshed&lt;/code&gt; is &lt;strong&gt;not an actual module&lt;/strong&gt; in Python, so you'll have to import it by checking &lt;code&gt;if TYPE_CHECKING&lt;/code&gt; to ensure python doesn't give a &lt;code&gt;ModuleNotFoundError&lt;/code&gt;. And since &lt;code&gt;SupportsLessThan&lt;/code&gt; won't be defined when Python runs, we had to use it as a string when passed to &lt;code&gt;TypeVar&lt;/code&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;At this point you might be interested in how you could implement one of your own such &lt;code&gt;SupportsX&lt;/code&gt; types. For that, we have another section below: Protocols.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Generic classes
&lt;/h2&gt;

&lt;p&gt;we implemented a simple Stack class in typing classes, but it only worked for integers. But we can very simply make it work for any type.&lt;/p&gt;

&lt;p&gt;To do that, we need mypy to understand what &lt;code&gt;T&lt;/code&gt; means inside the class. And for that, we need the class to extend &lt;code&gt;Generic[T]&lt;/code&gt;, and then provide the concrete type to &lt;code&gt;Stack&lt;/code&gt;:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;You can pass as many &lt;code&gt;TypeVar&lt;/code&gt;s to &lt;code&gt;Generic[...]&lt;/code&gt; as you need, for eg. to make a generic dictionary, you might use &lt;code&gt;class Dict(Generic[KT, VT]): ...&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Generic types
&lt;/h2&gt;

&lt;p&gt;Generic types (a.k.a. &lt;strong&gt;Type Aliases&lt;/strong&gt;) allow you to put a commonly used type in a variable -- and then use that variable as if it were that type.&lt;/p&gt;

&lt;p&gt;And mypy lets us do that very easily: with literally just an assignment. The generics parts of the type are automatically inferred.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;blockquote&gt;
&lt;p&gt;There is an upcoming syntax that makes it clearer that we're defining a type alias: &lt;code&gt;Vector: TypeAlias = Tuple[int, int]&lt;/code&gt;. This is available starting Python 3.10&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Just like how we were able to tell the TypeVar &lt;code&gt;T&lt;/code&gt; before to only support types that &lt;code&gt;SupportLessThan&lt;/code&gt;, we can also do that&lt;/p&gt;

&lt;p&gt;&lt;code&gt;AnyStr&lt;/code&gt; is a builtin &lt;a href="https://mypy.readthedocs.io/en/stable/generics.html?highlight=anystr#type-variables-with-value-restriction" rel="noopener noreferrer"&gt;restricted TypeVar&lt;/a&gt;, used to define a unifying type for functions that accept &lt;code&gt;str&lt;/code&gt; and &lt;code&gt;bytes&lt;/code&gt;:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;This is different from &lt;code&gt;Union[str, bytes]&lt;/code&gt;, because &lt;code&gt;AnyStr&lt;/code&gt; represents &lt;strong&gt;Any one of those two types at a time&lt;/strong&gt;, and thus doesn't &lt;code&gt;concat&lt;/code&gt; doesn't accept the first arg as &lt;code&gt;str&lt;/code&gt; and the second as &lt;code&gt;bytes&lt;/code&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  Advanced/Recursive type checking with &lt;code&gt;Protocol&lt;/code&gt; &lt;a&gt;
&lt;/a&gt;
&lt;/h1&gt;

&lt;p&gt;We implemented &lt;code&gt;FakeFuncs&lt;/code&gt; in the duck types section above, and we used &lt;code&gt;isinstance(FakeFuncs, Callable)&lt;/code&gt; to verify that the object indeed, was recognized as a callable.&lt;/p&gt;

&lt;p&gt;But what if we need to duck-type methods other than &lt;code&gt;__call__&lt;/code&gt;?&lt;/p&gt;

&lt;p&gt;If we want to do that with an entire class: That becomes harder. Say we want a "duck-typed class", that "has a get method that returns an int", and so on. We don't actually have access to the actual class for some reason, like maybe we're writing helper functions for an API library.&lt;/p&gt;

&lt;p&gt;To do that, we need to define a &lt;code&gt;Protocol&lt;/code&gt;:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Using this, we were able to type check out code, without ever needing a completed &lt;code&gt;Api&lt;/code&gt; implementaton.&lt;/p&gt;

&lt;p&gt;This is &lt;em&gt;extremely powerful&lt;/em&gt;. We're essentially defining the &lt;em&gt;structure&lt;/em&gt; of object we need, instead of what class it is from, or it inherits from. This gives us the flexibility of duck typing, but on the scale of an entire class.&lt;/p&gt;

&lt;p&gt;Remember &lt;code&gt;SupportsLessThan&lt;/code&gt;? if you check its implementation in &lt;code&gt;_typeshed&lt;/code&gt;, this is it:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Yeah, that's the entire implementaton.&lt;/p&gt;

&lt;p&gt;What this also allows us to do is define &lt;strong&gt;Recursive type definitions&lt;/strong&gt;. The simplest example would be a Tree:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Note that for this simple example, using Protocol wasn't necessary, as mypy is able to understand simple recursive structures. But for anything more complex than this, like an N-ary tree, you'll need to use Protocol.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Structural subtyping and all of its features are defined extremely well in &lt;a href="https://www.python.org/dev/peps/pep-0544/" rel="noopener noreferrer"&gt;PEP 544&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;
  
  
  Further learning
&lt;/h1&gt;

&lt;p&gt;If you're interested in reading even more about types, mypy has excellent &lt;a href="https://mypy.readthedocs.io/en/stable" rel="noopener noreferrer"&gt;documentation&lt;/a&gt;, and you should definitely read it for further learning, especially the section on &lt;a href="https://mypy.readthedocs.io/en/stable/generics.html" rel="noopener noreferrer"&gt;Generics&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I referenced a lot of &lt;a href="https://github.com/asottile" rel="noopener noreferrer"&gt;Anthony Sottile's&lt;/a&gt; videos in this for topics out of reach of this article. He has a &lt;a href="https://www.youtube.com/channel/UC46xhU1EH7aywEgvA9syS3w" rel="noopener noreferrer"&gt;YouTube channel&lt;/a&gt; where he posts short, and very informative videos about Python.&lt;/p&gt;

&lt;p&gt;You can find the source code the typing module &lt;a href="https://github.com/python/cpython/blob/main/Lib/typing.py" rel="noopener noreferrer"&gt;here&lt;/a&gt;, of all the typing duck types inside the &lt;a href="https://github.com/python/cpython/blob/main/Lib/_collections_abc.py" rel="noopener noreferrer"&gt;_collections_abc module&lt;/a&gt;, and of the extra ones in &lt;code&gt;_typeshed&lt;/code&gt; in the &lt;a href="https://github.com/python/typeshed/blob/master/stdlib/_typeshed/__init__.pyi" rel="noopener noreferrer"&gt;typeshed repo&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;A topic that I skipped over while talking about &lt;code&gt;TypeVar&lt;/code&gt; and generics, is &lt;em&gt;Variance&lt;/em&gt;. It's a topic in type theory that defines how subtypes and generics relate to each other. If you want to learn about it in depth, there's documentation in &lt;a href="https://mypy.readthedocs.io/en/stable/generics.html#variance-of-generic-types" rel="noopener noreferrer"&gt;mypy docs&lt;/a&gt; of course, and there's two more blogs I found which help grasp the concept, &lt;a href="https://blog.daftcode.pl/covariance-contravariance-and-invariance-the-ultimate-python-guide-8fabc0c24278" rel="noopener noreferrer"&gt;here&lt;/a&gt; and &lt;a href="https://blog.magrathealabs.com/pythons-covariance-and-contravariance-b422c63f57ac" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;A bunch of this material was cross-checked using &lt;a href="https://docs.python.org/3" rel="noopener noreferrer"&gt;Python's official documentation&lt;/a&gt;, and honestly their docs are always great. Also, the "Quick search" feature works surprisingly well.&lt;/p&gt;

&lt;p&gt;There's also quite a few typing PEPs you can read, starting with the kingpin: &lt;a href="https://www.python.org/dev/peps/pep-0484/" rel="noopener noreferrer"&gt;PEP 484&lt;/a&gt;, and the accompanying &lt;a href="https://www.python.org/dev/peps/pep-0526/" rel="noopener noreferrer"&gt;PEP 526&lt;/a&gt;. Other PEPs I've mentioned in the article above are &lt;a href="https://www.python.org/dev/peps/pep-0585/" rel="noopener noreferrer"&gt;PEP 585&lt;/a&gt;, &lt;a href="https://www.python.org/dev/peps/pep-0563/" rel="noopener noreferrer"&gt;PEP 563&lt;/a&gt;, &lt;a href="https://www.python.org/dev/peps/pep-0420/" rel="noopener noreferrer"&gt;PEP 420&lt;/a&gt; and &lt;a href="https://www.python.org/dev/peps/pep-0544/" rel="noopener noreferrer"&gt;PEP 544&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;And that's it!&lt;/p&gt;

&lt;p&gt;I've worked pretty hard on this article, distilling down everything I've learned about mypy in the past year, into a single source of knowledge. If you have any doubts, thoughts, or suggestions, be sure to comment below and I'll get back to you.&lt;/p&gt;

&lt;p&gt;Also, if you read the whole article till here, Thank you! And congratulations, you now know almost everything you'll need to be able to write fully typed Python code in the future. I hope you liked it ✨&lt;/p&gt;

</description>
      <category>python</category>
      <category>mypy</category>
      <category>types</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Does Python need types?</title>
      <dc:creator>Tushar Sadhwani</dc:creator>
      <pubDate>Wed, 28 Apr 2021 19:50:15 +0000</pubDate>
      <link>https://forem.com/tusharsadhwani/does-python-need-types-59if</link>
      <guid>https://forem.com/tusharsadhwani/does-python-need-types-59if</guid>
      <description>&lt;p&gt;I'm a huge fan of Python. It's by far the simplest general purpose language, that you can just pick up and start building amazing things with.&lt;/p&gt;

&lt;p&gt;But for the past year or so, I've been working on frontend projects, and I've really enjoyed using &lt;a href="https://www.typescriptlang.org" rel="noopener noreferrer"&gt;Typescript&lt;/a&gt;. It's essentially JavaScript, but with fancy features built on top of it like &lt;em&gt;Static Type checking&lt;/em&gt; and &lt;em&gt;Null safety&lt;/em&gt;, and it was &lt;em&gt;awesome&lt;/em&gt; how much it helped in writing robust, bug free code.&lt;/p&gt;

&lt;p&gt;So I went out to find if Python has such an equivalent, and sure enough, there was.&lt;/p&gt;

&lt;p&gt;It's called &lt;a href="https://mypy-lang.org" rel="noopener noreferrer"&gt;mypy&lt;/a&gt;, and it is amazing. It works so well in-fact, that I can never go back to writing plain Python now — and this article will be your introduction to it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;But before all that&lt;/strong&gt;, let's figure out what's the deal with &lt;em&gt;Types&lt;/em&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why types?
&lt;/h2&gt;

&lt;p&gt;What it essentially means is if you have a type system, &lt;strong&gt;every variable has a pre-decided type associated with it&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffdmzm8gner72499j5i3h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffdmzm8gner72499j5i3h.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;
Untyped vs. typed Python code



&lt;blockquote&gt;
&lt;p&gt;Note that, while this might not look like it, the typed version is perfectly valid Python code.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;What it also means, is you can't pass values of the wrong type anywhere. The type checker doesn't let you.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcgam11h9xoxqyhizstw2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcgam11h9xoxqyhizstw2.png" alt="image"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;Which is extremely valuable if you think about it - I've lost count how many &lt;code&gt;TypeError&lt;/code&gt;'s I've seen in Python over the years!&lt;/p&gt;

&lt;p&gt;Just having the confidence that there's no such place in your code where accidentally passed a &lt;code&gt;str&lt;/code&gt; where an &lt;code&gt;int&lt;/code&gt; was expected, eliminates an entire class of bugs from your codebase.&lt;/p&gt;




&lt;p&gt;Not only that - you get a bunch of other benefits, namely:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Self-documenting code&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;None&lt;/code&gt;-awareness&lt;/li&gt;
&lt;li&gt;Better autocompletion and IDE support&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I'll go over all these points in detail.&lt;/p&gt;

&lt;h3&gt;
  
  
  Self-documenting code
&lt;/h3&gt;

&lt;p&gt;Imagine you have this piece of code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;add_orders&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;orders&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;orders&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pending_ids&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Seems rather simple, doesn't it? We seem to have a list of &lt;code&gt;order&lt;/code&gt;'s, and we add each order's id to a set called &lt;code&gt;pending_ids&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;But what are &lt;code&gt;order&lt;/code&gt;'s here...&lt;/p&gt;

&lt;p&gt;It's hard to tell. In a large codebase, you might have to search pretty hard to find out which part of the code is calling &lt;code&gt;add_orders&lt;/code&gt;, and where the data in that is coming from, to eventually find out that it's supposed to be just a &lt;code&gt;namedtuple&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;How about this instead:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Order&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;add_orders&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;orders&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Order&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;orders&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pending_ids&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now it's instantly clear, that everywhere &lt;code&gt;add_orders&lt;/code&gt; is used, it's going to be exactly of that type.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;None&lt;/code&gt;-awareness
&lt;/h3&gt;

&lt;p&gt;What I mean by this, is that not only can you not pass wrong types of values around, you also can't pass values that could be &lt;code&gt;None&lt;/code&gt;, to places that don't expect the value to be possibly &lt;code&gt;None&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Here's an example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;User&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;namedtuple&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;User&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;favorites&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;fetch_users&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;users&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;user_dict&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;get_user_from_api&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;user_dict&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Anonymous&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="n"&gt;favorites&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;user_dict&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;favorites&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;print_favorite_colors&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;favorites&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;color&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="n"&gt;users&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;fetch_users&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="nf"&gt;print_favorite_colors&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;... and on first glance, this looks fine. We're using &lt;code&gt;.get&lt;/code&gt; so we shouldn't get a &lt;code&gt;KeyError&lt;/code&gt; anywhere, so we should be fine, right?&lt;/p&gt;

&lt;p&gt;Now here's the typed version of the same code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;NamedTuple&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="n"&gt;favorites&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Optional&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;fetch_users&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="n"&gt;users&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;user_dict&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;get_user_from_api&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;user_dict&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Anonymous&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="n"&gt;favorites&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;user_dict&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;favorites&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;print_favorite_colors&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;favorites&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;color&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;


&lt;span class="n"&gt;users&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;fetch_users&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="nf"&gt;print_favorite_colors&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And as soon as you add types, you see one error:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffcmm87dc0gdnwr7k45j1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffcmm87dc0gdnwr7k45j1.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You forgot that &lt;code&gt;user.favorites&lt;/code&gt; could be None, which would crash your entire application.&lt;/p&gt;

&lt;p&gt;Good thing mypy caught it before your clients did.&lt;/p&gt;

&lt;h3&gt;
  
  
  Better autocompletion and IDE support
&lt;/h3&gt;

&lt;p&gt;This is honestly my favorite part of working with typed Python. The amount of autocompletion static types give me is awesome, and it increases my productivity ten-fold, because I rarely have to open the documentation anymore.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Faf50k2xhu0n7oz5w3f83.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Faf50k2xhu0n7oz5w3f83.png" alt="image"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;h2&gt;
  
  
  Where can I use it?
&lt;/h2&gt;

&lt;p&gt;Now I can hear you saying, "All of this sounds very cool. But where can I use this mypy-thing in my Python codebase?"&lt;/p&gt;

&lt;p&gt;And turns out, &lt;strong&gt;you can start gradually adding types to your existing Python codebase&lt;/strong&gt;, one function and one class at a time. It will infer as much information as it can from the amount of type information it has, and will reduce your bugs no matter how small you start.&lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;So, this was my introduction to you, to the world of static type checking in Python. Are you interested in learning more about it? I'll be dropping a detailed guide to mypy very soon, so stay tuned.&lt;/p&gt;

&lt;p&gt;I'd also love to hear your thoughs on this article, so let me know what you think about mypy down in the comments.&lt;/p&gt;

</description>
      <category>python</category>
      <category>types</category>
      <category>mypy</category>
    </item>
    <item>
      <title>Connecting Android Apps to localhost, Simplified</title>
      <dc:creator>Tushar Sadhwani</dc:creator>
      <pubDate>Sat, 17 Apr 2021 19:20:08 +0000</pubDate>
      <link>https://forem.com/tusharsadhwani/connecting-android-apps-to-localhost-simplified-57lm</link>
      <guid>https://forem.com/tusharsadhwani/connecting-android-apps-to-localhost-simplified-57lm</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;P.S. if you're in a hurry, find the correct solution here&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I was working on a full stack side project a few months ago, and I wanted to make API requests from my android app to my desktop, and for some reason &lt;code&gt;localhost:8000&lt;/code&gt; wasn't simply accessible by my phone.&lt;/p&gt;

&lt;p&gt;Well, understandable, I know that every device's localhost is independent and cannot be accessed by your home network (your Wi-Fi, for example). So the localhost on my laptop won't be able to access the localhost on my phone.&lt;/p&gt;

&lt;p&gt;So, I asked Google for help. And I got a large number of solutions, the most sensible one being "use the internal IP address of your PC", et voilà.&lt;/p&gt;

&lt;h1&gt;
  
  
  The Bad way
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftgakgpfuw4eyvjud9tin.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftgakgpfuw4eyvjud9tin.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;
Use ipconfig if you're on windows



&lt;p&gt;Running &lt;code&gt;ip addr&lt;/code&gt; on my machine tells me that the laptop's internal IP is &lt;code&gt;192.168.29.76&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;And sure enough, as long as both devices were using the same Wi-Fi network, accessing &lt;code&gt;http://192.168.29.76:8000&lt;/code&gt; instead of &lt;code&gt;http://localhost:8000&lt;/code&gt; did work. My Android app can now make web requests to my local backend server 🎉&lt;/p&gt;

&lt;p&gt;But this solution is... a bit unstable.&lt;/p&gt;

&lt;p&gt;The internal IP of your laptop can keep changing whenever it connects to Wi-Fi, depending on various factors. And everytime it changes, you have to change the URL in your app's code, which is not ideal.&lt;/p&gt;

&lt;p&gt;There's other ways as well like using ngrok, but it faces similar issues.&lt;/p&gt;

&lt;h1&gt;
  
  
  The Correct, easy way
&lt;/h1&gt;

&lt;p&gt;use &lt;code&gt;adb reverse&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Yup, that's it.&lt;/p&gt;

&lt;p&gt;Connect your android device to your pc via USB, ensure you have &lt;a href="https://www.xda-developers.com/install-adb-windows-macos-linux/" rel="noopener noreferrer"&gt;adb setup&lt;/a&gt;, and run this in your terminal:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

adb reverse tcp:8000 tcp:8000


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Now, your mobile can access &lt;code&gt;localhost:8000&lt;/code&gt;, just like your PC. (you can replace &lt;code&gt;8000&lt;/code&gt; with whichever port you want to forward)&lt;/p&gt;

&lt;h1&gt;
  
  
  Why did nobody tell me this?
&lt;/h1&gt;

&lt;p&gt;Yeah, I was also surprised when I was unable to find anyone on Google or StackOverflow mentioning the existence of &lt;code&gt;adb reverse&lt;/code&gt; when I tried to look for it.&lt;/p&gt;

&lt;p&gt;Which is why I wrote this blog. Now hopefully, &lt;code&gt;adb reverse&lt;/code&gt; will become more popular.&lt;/p&gt;

&lt;p&gt;If you know why &lt;code&gt;adb reverse&lt;/code&gt; isn't as popular, let me know. Also, if you know another android developer that should know about this little productivity hack, why not share this blog with them? :P&lt;/p&gt;




&lt;p&gt;Cover image courtesy of &lt;a href="https://unsplash.com/@ffstop?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Fotis Fotopoulos&lt;/a&gt; on &lt;a href="https://unsplash.com/?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;&lt;/p&gt;

</description>
      <category>android</category>
      <category>testing</category>
    </item>
    <item>
      <title>How to setup PostgreSQL and PGAdmin on Manjaro Linux / Arch</title>
      <dc:creator>Tushar Sadhwani</dc:creator>
      <pubDate>Sat, 26 Sep 2020 18:48:35 +0000</pubDate>
      <link>https://forem.com/tusharsadhwani/how-to-setup-postgresql-on-manjaro-linux-arch-412l</link>
      <guid>https://forem.com/tusharsadhwani/how-to-setup-postgresql-on-manjaro-linux-arch-412l</guid>
      <description>&lt;p&gt;This guide is here just because I've messed up the installs on arch before, and turns out it's actually pretty easy to do.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1 - Install the dependencies
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;sudo pacman -S yay
yay postgresql pgadmin4
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This should automatically setup your postgres user and group.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2 - Setup postgres service
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;sudo -u postgres -i #&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;login as postgres
&lt;span class="gp"&gt;initdb --locale $&lt;/span&gt;LANG &lt;span class="nt"&gt;-E&lt;/span&gt; UTF8 &lt;span class="nt"&gt;-D&lt;/span&gt; &lt;span class="s1"&gt;'/var/lib/postgres/data/'&lt;/span&gt;
&lt;span class="go"&gt;exit

sudo systemctl enable --now postgresql
&lt;/span&gt;&lt;span class="gp"&gt;sudo systemctl status postgresql #&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;to check &lt;span class="k"&gt;for &lt;/span&gt;any errors
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 3 - Setup password
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;psql -U postgres

&lt;/span&gt;&lt;span class="gp"&gt;postgres=#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\p&lt;/span&gt;assword &lt;span class="c"&gt;# to set password&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 4 - Setup connection security
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;su
&lt;span class="go"&gt;
&lt;/span&gt;&lt;span class="gp"&gt;#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; /var/lib/postgres/data
&lt;span class="gp"&gt;#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;cp &lt;/span&gt;pg_hba.conf pg_hba.conf.backup &lt;span class="c"&gt;# in case you mess up&lt;/span&gt;
&lt;span class="gp"&gt;#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;nano pg_hba.conf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your default pg_hba.conf might look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; TYPE  DATABASE        USER            ADDRESS                 METHOD

# "local" is for Unix domain socket connections only
local   all             all                                     trust
# IPv4 local connections:
host    all             all             127.0.0.1/32            trust
# IPv6 local connections:
host    all             all             ::1/128                 trust
# Allow replication connections from localhost, by a user with the
# replication privilege.
local   replication     all                                     trust
host    replication     all             127.0.0.1/32            trust
host    replication     all             ::1/128                 trust
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;"Method" is set to trust, meaning it won't ask for the password to anyone. To fix that, change the method from &lt;code&gt;trust&lt;/code&gt; to &lt;code&gt;md5&lt;/code&gt; everywhere.&lt;/p&gt;

&lt;p&gt;And that should be it for postgres!&lt;/p&gt;

&lt;h2&gt;
  
  
  Bonus: shortcuts
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;psql dbname postgres &lt;span class="c"&gt;# to directly open a database&lt;/span&gt;
&lt;span class="go"&gt;
&lt;/span&gt;&lt;span class="gp"&gt;postgres=#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\c&lt;/span&gt;                       &lt;span class="c"&gt;# see current database&lt;/span&gt;
&lt;span class="gp"&gt;postgres=#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\l&lt;/span&gt;                       &lt;span class="c"&gt;# see list of databases&lt;/span&gt;
&lt;span class="gp"&gt;postgres=#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\c&lt;/span&gt; dbname                &lt;span class="c"&gt;# set database&lt;/span&gt;
&lt;span class="gp"&gt;postgres=#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;create database dbname&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c"&gt;# create database&lt;/span&gt;
&lt;span class="gp"&gt;postgres=#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\d&lt;/span&gt;t                      &lt;span class="c"&gt;# see list of tables&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 6 - PgAdmin
&lt;/h2&gt;

&lt;p&gt;Open up pgadmin, click on "Add New Server", and add the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Host: localhost
Port: 5432
Maintenance database: postgres
Username: postgres
Password: &amp;lt;your password&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And PgAdmin should work just fine.&lt;/p&gt;

</description>
      <category>linux</category>
      <category>postgres</category>
      <category>archlinux</category>
    </item>
    <item>
      <title>How I made my own URL shortener for free</title>
      <dc:creator>Tushar Sadhwani</dc:creator>
      <pubDate>Tue, 01 Sep 2020 13:47:31 +0000</pubDate>
      <link>https://forem.com/tusharsadhwani/how-i-made-my-own-url-shortener-for-free-293p</link>
      <guid>https://forem.com/tusharsadhwani/how-i-made-my-own-url-shortener-for-free-293p</guid>
      <description>&lt;p&gt;URL shorteners are great. You can take a long URL and make it 6–8 characters, you know the drill.&lt;/p&gt;

&lt;p&gt;And the free URL shorteners are pretty nice too! &lt;strong&gt;bit.ly&lt;/strong&gt; is what I used, and it did its job pretty well, but free public shorteners have a few issues:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Finding the perfect short URL is hard: most of the short ones that make sense, are usually already taken.&lt;/li&gt;
&lt;li&gt;  the URLs are hard to update: &lt;em&gt;(and I don’t know if this is a bit.ly specific issue)&lt;/em&gt;, &lt;strong&gt;but you can’t change the URL the short link points to&lt;/strong&gt;, once it has been created.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So I decided to make my own instead.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Getting a short domain
&lt;/h2&gt;

&lt;p&gt;The entire point of a URL shortener is to be short, and for that you need to get a short domain name. Fortunately, services like &lt;a href="http://dot.tk" rel="noopener noreferrer"&gt;Dot tk&lt;/a&gt; exist, which provide domains from various TLDs at no cost. (If you’re a university student, you can also use the GitHub Student pack for domains like &lt;strong&gt;.me&lt;/strong&gt;).&lt;/p&gt;

&lt;p&gt;I got the domain &lt;strong&gt;tshr.me&lt;/strong&gt; for myself.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F6x3o1hq4ma6nk26vqmy7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F6x3o1hq4ma6nk26vqmy7.png" alt="free short domains for everyone!"&gt;&lt;/a&gt;&lt;em&gt;free short domains for everyone!&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Making the URLs redirect
&lt;/h2&gt;

&lt;p&gt;Traditionally, URLs run off of a hosted web server, which are also relatively easy to make, &lt;a href="https://www.youtube.com/watch?v=gq5yubc1u18" rel="noopener noreferrer"&gt;as shown in this video for example.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But the issue with a web server solution is that you have to host it, and &lt;strong&gt;hosting ain’t free.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Sure, there’s services like &lt;a href="https://heroku.com" rel="noopener noreferrer"&gt;Heroku&lt;/a&gt;, which is a great platform, but it’s inadequate for our use case:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Its free dynos only run for 550 hours a month, which means you either have to add your credit card information, or there will be no guarantees that your links will always work.&lt;/li&gt;
&lt;li&gt;  Free dynos &lt;strong&gt;go to sleep after 1 hour of inactivity&lt;/strong&gt;, meaning if someone tries to access your URLs after a long time, they might have to wait a significantly long time before they get redirected. &lt;em&gt;(This can possibly be fixed by scheduling&lt;/em&gt; &lt;a href="https://cron-job.org/" rel="noopener noreferrer"&gt;&lt;em&gt;cron jobs&lt;/em&gt;&lt;/a&gt; &lt;em&gt;to ping the server, but it’s not a great solution.)&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;  And most importantly: &lt;strong&gt;Heroku’s free tier doesn’t support custom domain names!&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So we will have to use a different approach.&lt;/p&gt;

&lt;h2&gt;
  
  
  GitHub to the rescue — Part 1
&lt;/h2&gt;

&lt;p&gt;You should be knowing already, that GitHub can hosts static websites for free on its platform called &lt;strong&gt;GitHub Pages&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;But you might be thinking, &lt;em&gt;“Yes, I know you can use GitHub for static websites, but you can’t use it to host web servers, dummy.”&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;… or can you. 🤨&lt;/p&gt;

&lt;p&gt;Nah, you can’t host a web server on GitHub, but you can do the next best thing: host a static URL shortener.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;This script, when ran in a browser, will redirect you to &lt;strong&gt;medium.com&lt;/strong&gt; immediately. Put this file in a repository on GitHub, add the domain name &lt;strong&gt;tshr.me&lt;/strong&gt; to the GitHub Pages custom domain field, and BOOM!💥&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;tshr.me&lt;/strong&gt; now redirects to &lt;strong&gt;medium.com&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;… you don’t seem very impressed. Don’t worry, we’ll get there.&lt;/p&gt;

&lt;h2&gt;
  
  
  Just Automate it (with Python!)
&lt;/h2&gt;

&lt;p&gt;Here comes the fun part:&lt;/p&gt;

&lt;p&gt;If we could generate all the static short links we want that use the above technique to redirect to the actual URL we want, then this technique might be of some actual use, right?&lt;/p&gt;

&lt;p&gt;So I wrote a python scripts that takes in JSON data of various short links and their corresponding redirect URLs, and generates all the HTML pages for me.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;The corresponding JSON data looks like this:&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Now we’re talking! Running this script generates your HTML redirects and places them neatly in a folder, which you can upload to your GitHub.&lt;/p&gt;

&lt;p&gt;But this isn’t exactly the most convenient, right? Every time you have to update your URLs, you have to &lt;em&gt;update the JSON file, run the python code, push the folder to GitHub…&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;It just sounds really cumbersome. And it is.&lt;/p&gt;

&lt;h2&gt;
  
  
  GitHub to the rescue — Part 2
&lt;/h2&gt;

&lt;p&gt;Here’s where we use GitHub’s slightly less known, but really powerful tool: &lt;strong&gt;GitHub Actions.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fy4lsjmlqpfxovxbz8gd2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fy4lsjmlqpfxovxbz8gd2.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;GitHub Actions is GitHub’s super powerful builtin CI/CD tool. It runs a virtual machine for you, that can pull your code, test it, and deploy it, every single time you push an update to your repository. All for no cost at all.&lt;/p&gt;

&lt;p&gt;What we are going to do is use its Python workflow that runs our HTML generator script for us, and use a plugin to create a separate GitHub Pages branch to deploy it to, automatically.&lt;/p&gt;

&lt;p&gt;Using this, we can update our short links by simply editing and saving our links.json file, everything else will be handled for us by GitHub.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;But first,&lt;/strong&gt; we need to make some arrangements.&lt;/p&gt;

&lt;h2&gt;
  
  
  Deploy Keys: a short explanation
&lt;/h2&gt;

&lt;p&gt;GitHub has a feature called Deploy Keys, which are essentially just SSH keys that have read/write access to your repository, so a computer that has that key can push code to your repo directly.&lt;/p&gt;

&lt;p&gt;To add a deploy key to your GitHub repo, follow these simple steps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Generate an SSH key: 
open your terminal/command prompt and type &lt;code&gt;ssh-keygen&lt;/code&gt; 
Give it any name you like (using the repository name would be good), use an empty passphrase for it, and keep everything else default.
This will generate a private key file, and a public &lt;code&gt;.pub&lt;/code&gt; file, both with the same name.
&lt;em&gt;(If the command&lt;/em&gt; &lt;code&gt;_ssh-keygen_&lt;/code&gt; &lt;em&gt;doesn’t work, you might have to install OpenSSH on your system)&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fhyssr7nq0gmbhbtctpho.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fhyssr7nq0gmbhbtctpho.png" alt="You just generated an SSH public-private key pair!"&gt;&lt;/a&gt;&lt;/p&gt;
You just generated an SSH public-private key pair!



&lt;ul&gt;
&lt;li&gt;  Open your repository settings, and go to the Deploy Keys tab.
It should look something like this:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F9vd0q51ub8by6fdifwvf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F9vd0q51ub8by6fdifwvf.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Click on “Add deploy key” on the top right, and copy-paste the entire contents of the &lt;code&gt;.pub&lt;/code&gt; file that you just generated. &lt;strong&gt;(Make sure to click the “write access” checkbox)&lt;/strong&gt;:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F7mjl0gb479g8q7ksgyn3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F7mjl0gb479g8q7ksgyn3.png" alt="The title of the key doesn’t really matter here."&gt;&lt;/a&gt;&lt;/p&gt;
The title of the key doesn’t really matter here.



&lt;ul&gt;
&lt;li&gt;  Then head down to the &lt;strong&gt;Secrets&lt;/strong&gt; section of your repository settings, and add a new secret named &lt;code&gt;ACTIONS_DEPLOY_KEY&lt;/code&gt;, and copy your private key into it. It should look something like:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fznap67oz7d72ls2mmv7i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fznap67oz7d72ls2mmv7i.png" alt="That’s a long secret."&gt;&lt;/a&gt;&lt;/p&gt;
That’s a long secret.



&lt;p&gt;And that’s it! We can now get into &lt;strong&gt;the Action&lt;/strong&gt; (pun intended).&lt;/p&gt;

&lt;h2&gt;
  
  
  Final step: Setting up the GitHub Action
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fbejlitlom7cg47ucxu2x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fbejlitlom7cg47ucxu2x.png" alt="The workflow we will be using"&gt;&lt;/a&gt;&lt;/p&gt;
The workflow we will be using



&lt;p&gt;Simply navigate to the Actions tab, and click on the Python Application workflow. Replace its contents with the ones provided below:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;And we’re done!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You can create your own free URL shortener by simply forking my repository:&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://github.com/tusharsadhwani/url-shortener" rel="noopener noreferrer"&gt;https://github.com/tusharsadhwani/url-shortener&lt;/a&gt;,&lt;/p&gt;

&lt;p&gt;adding a secret and a deploy key to your repo with write access, and changing the website name from &lt;strong&gt;tshr.me&lt;/strong&gt; to whatever your domain name is, in the &lt;code&gt;main.py&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;Thanks for reading this article!&lt;br&gt;&lt;br&gt;
Big thanks from my side to &lt;a href="https://www.youtube.com/channel/UCLNgu_OupwoeESgtab33CCw" rel="noopener noreferrer"&gt;Coding Garden&lt;/a&gt;, whose videos motivated me to make this project in the first place, and &lt;a href="https://medium.com/@cmichel/how-to-deploy-a-create-react-app-with-github-actions-5e01f7a7b6b" rel="noopener noreferrer"&gt;this article&lt;/a&gt;, which led me to the free hack that I came up with. Also thanks to &lt;a href="https://github.com/wojpawlik" rel="noopener noreferrer"&gt;Wojtek Pawlik&lt;/a&gt; &lt;em&gt;(GingerPlusPlus)&lt;/em&gt; for suggesting a non-javascript method for redirects.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>github</category>
    </item>
  </channel>
</rss>
