<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">

  <title>Real Python</title>
  <link href="https://realpython.com/atom.xml" rel="self"/>
  <link href="https://realpython.com/"/>
  <updated>2019-04-22T14:00:00+00:00</updated>
  <id>https://realpython.com/</id>
  <author>
    <name>Real Python</name>
  </author>

  
    <entry>
      <title>A Beginner’s Guide to the Python time Module</title>
      <id>https://realpython.com/python-time-module/</id>
      <link href="https://realpython.com/python-time-module/"/>
      <updated>2019-04-22T14:00:00+00:00</updated>
      <summary>In this tutorial, you&#39;ll learn how to use the Python time module to represent dates and times in your application, manage code execution, and measure performance.</summary>
      <content type="html">
        &lt;p&gt;The Python &lt;code&gt;time&lt;/code&gt; module provides many ways of representing time in code, such as objects, numbers, and strings. It also provides functionality other than representing time, like waiting during code execution and measuring the efficiency of your code.&lt;/p&gt;
&lt;p&gt;This article will walk you through the most commonly used functions and objects in &lt;code&gt;time&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;By the end of this article, you&amp;rsquo;ll be able to:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Understand&lt;/strong&gt; core concepts at the heart of working with dates and times, such as epochs, time zones, and daylight savings time&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Represent&lt;/strong&gt; time in code using floats, tuples, and &lt;code&gt;struct_time&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Convert&lt;/strong&gt; between different time representations&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Suspend&lt;/strong&gt; thread execution&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Measure&lt;/strong&gt; code performance using &lt;code&gt;perf_counter()&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You&amp;rsquo;ll start by learning how you can use a floating point number to represent time.&lt;/p&gt;
&lt;div class=&quot;alert alert-warning&quot; role=&quot;alert&quot;&gt;&lt;p&gt;&lt;strong&gt;Free Bonus:&lt;/strong&gt; &lt;a href=&quot;&quot; class=&quot;alert-link&quot; data-toggle=&quot;modal&quot; data-target=&quot;#modal-python-cheat-sheet-experiment&quot; data-focus=&quot;false&quot;&gt;Click here to get our free Python Cheat Sheet&lt;/a&gt; that shows you the basics of Python 3, like working with data types, dictionaries, lists, and Python functions.&lt;/p&gt;&lt;/div&gt;

&lt;h2 id=&quot;dealing-with-python-time-using-seconds&quot;&gt;Dealing With Python Time Using Seconds&lt;/h2&gt;
&lt;p&gt;One of the ways you can manage the concept of Python time in your application is by using a floating point number that represents the number of seconds that have passed since the beginning of an era&amp;mdash;that is, since a certain starting point.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s dive deeper into what that means, why it&amp;rsquo;s useful, and how you can use it to implement logic, based on Python time, in your application.&lt;/p&gt;
&lt;h3 id=&quot;the-epoch&quot;&gt;The Epoch&lt;/h3&gt;
&lt;p&gt;You learned in the previous section that you can manage Python time with a floating point number representing elapsed time since the beginning of an era.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.merriam-webster.com/dictionary/era&quot;&gt;Merriam-Webster&lt;/a&gt; defines an era as:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A fixed point in time from which a series of years is reckoned&lt;/li&gt;
&lt;li&gt;A system of chronological notation computed from a given date as basis&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The important concept to grasp here is that, when dealing with Python time, you&amp;rsquo;re considering a period of time identified by a starting point. In computing, you call this starting point the &lt;strong&gt;epoch&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;The epoch, then, is the starting point against which you can measure the passage of time.&lt;/p&gt;
&lt;p&gt;For example, if you define the epoch to be midnight on January 1, 1970 UTC&amp;mdash;the epoch as defined on Windows and most UNIX systems&amp;mdash;then you can represent midnight on January 2, 1970 UTC as &lt;code&gt;86400&lt;/code&gt; seconds since the epoch.&lt;/p&gt;
&lt;p&gt;This is because there are 60 seconds in a minute, 60 minutes in an hour, and 24 hours in a day. January 2, 1970 UTC is only one day after the epoch, so you can apply basic math to arrive at that result:&lt;/p&gt;
&lt;div class=&quot;highlight python pycon&quot;&gt;&lt;span class=&quot;repl-toggle&quot; title=&quot;Toggle REPL prompts and output&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;60&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;60&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;24&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;86400&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;It is also important to note that you can still represent time before the epoch. The number of seconds would just be negative.&lt;/p&gt;
&lt;p&gt;For example, you would represent midnight on December 31, 1969 UTC (using an epoch of January 1, 1970) as &lt;code&gt;-86400&lt;/code&gt; seconds.&lt;/p&gt;
&lt;p&gt;While January 1, 1970 UTC is a common epoch, it is not the only epoch used in computing. In fact, different operating systems, filesystems, and APIs sometimes use different epochs.&lt;/p&gt;
&lt;p&gt;As you saw before, UNIX systems define the epoch as January 1, 1970. The Win32 API, on the other hand, defines the epoch as &lt;a href=&quot;https://blogs.msdn.microsoft.com/oldnewthing/20090306-00/?p=18913/&quot;&gt;January 1, 1601&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;You can use &lt;code&gt;time.gmtime()&lt;/code&gt; to determine your system&amp;rsquo;s epoch:&lt;/p&gt;
&lt;div class=&quot;highlight python pycon&quot;&gt;&lt;span class=&quot;repl-toggle&quot; title=&quot;Toggle REPL prompts and output&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;time&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gmtime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;time.struct_time(tm_year=1970, tm_mon=1, tm_mday=1, tm_hour=0, tm_min=0, tm_sec=0, tm_wday=3, tm_yday=1, tm_isdst=0)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You&amp;rsquo;ll learn about &lt;code&gt;gmtime()&lt;/code&gt; and &lt;code&gt;struct_time&lt;/code&gt; throughout the course of this article. For now, just know that you can use &lt;code&gt;time&lt;/code&gt; to discover the epoch using this function.&lt;/p&gt;
&lt;p&gt;Now that you understand more about how to measure time in seconds using an epoch, let&amp;rsquo;s take a look at Python&amp;rsquo;s &lt;code&gt;time&lt;/code&gt; module to see what functions it offers that help you do so.&lt;/p&gt;
&lt;h3 id=&quot;python-time-in-seconds-as-a-floating-point-number&quot;&gt;Python Time in Seconds as a Floating Point Number&lt;/h3&gt;
&lt;p&gt;First, &lt;code&gt;time.time()&lt;/code&gt; returns the number of seconds that have passed since the epoch. The return value is a floating point number to account for fractional seconds:&lt;/p&gt;
&lt;div class=&quot;highlight python pycon&quot;&gt;&lt;span class=&quot;repl-toggle&quot; title=&quot;Toggle REPL prompts and output&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;time&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;time&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;1551143536.9323719&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The number you get on your machine may be very different because the reference point considered to be the epoch may be very different.&lt;/p&gt;
&lt;div class=&quot;alert alert-primary&quot; role=&quot;alert&quot;&gt;
&lt;p&gt;&lt;strong&gt;Further Reading:&lt;/strong&gt; Python 3.7 introduced &lt;a href=&quot;https://realpython.com/python37-new-features/#timing-precision&quot;&gt;&lt;code&gt;time_ns()&lt;/code&gt;&lt;/a&gt;, which returns an integer value representing the same elapsed time since the epoch, but in nanoseconds rather than seconds.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;Measuring time in seconds is useful for a number of reasons:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You can use a float to calculate the difference between two points in time.&lt;/li&gt;
&lt;li&gt;A float is easily &lt;a href=&quot;https://en.wikipedia.org/wiki/Serialization&quot;&gt;serializable&lt;/a&gt;, meaning that it can be stored for data transfer and come out intact on the other side.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Sometimes, however, you may want to see the current time represented as a string. To do so, you can pass the number of seconds you get from &lt;code&gt;time()&lt;/code&gt; into &lt;code&gt;time.ctime()&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;python-time-in-seconds-as-a-string-representing-local-time&quot;&gt;Python Time in Seconds as a String Representing Local Time&lt;/h3&gt;
&lt;p&gt;As you saw before, you may want to convert the Python time, represented as the number of elapsed seconds since the epoch, to a &lt;a href=&quot;https://realpython.com/python-strings/&quot;&gt;string&lt;/a&gt;. You can do so using &lt;code&gt;ctime()&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight python pycon&quot;&gt;&lt;span class=&quot;repl-toggle&quot; title=&quot;Toggle REPL prompts and output&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;time&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ctime&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ctime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;&amp;#39;Mon Feb 25 19:11:59 2019&amp;#39;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Here, you&amp;rsquo;ve recorded the current time in seconds into the variable &lt;code&gt;t&lt;/code&gt;, then passed &lt;code&gt;t&lt;/code&gt; as an argument to &lt;code&gt;ctime()&lt;/code&gt;, which returns a string representation of that same time.&lt;/p&gt;
&lt;div class=&quot;alert alert-primary&quot; role=&quot;alert&quot;&gt;
&lt;p&gt;&lt;strong&gt;Technical Detail:&lt;/strong&gt; The argument, representing seconds since the epoch, is optional according to the &lt;code&gt;ctime()&lt;/code&gt; definition. If you don&amp;rsquo;t pass an argument, then &lt;code&gt;ctime()&lt;/code&gt; uses the return value of &lt;code&gt;time()&lt;/code&gt; by default. So, you could simplify the example above:&lt;/p&gt;
&lt;div class=&quot;highlight python pycon&quot;&gt;&lt;span class=&quot;repl-toggle&quot; title=&quot;Toggle REPL prompts and output&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;time&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ctime&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ctime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;&amp;#39;Mon Feb 25 19:11:59 2019&amp;#39;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;/div&gt;
&lt;p&gt;The string representation of time, also known as a &lt;strong&gt;timestamp&lt;/strong&gt;, returned by &lt;code&gt;ctime()&lt;/code&gt; is formatted with the following structure:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Day of the week:&lt;/strong&gt; &lt;code&gt;Mon&lt;/code&gt; (&lt;code&gt;Monday&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Month of the year:&lt;/strong&gt; &lt;code&gt;Feb&lt;/code&gt; (&lt;code&gt;February&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Day of the month:&lt;/strong&gt; &lt;code&gt;25&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Hours, minutes, and seconds using the &lt;a href=&quot;https://en.wikipedia.org/wiki/24-hour_clock&quot;&gt;24-hour clock&lt;/a&gt; notation:&lt;/strong&gt; &lt;code&gt;19:11:59&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Year:&lt;/strong&gt; &lt;code&gt;2019&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The previous example displays the timestamp of a particular moment captured from a computer in the South Central region of the United States. But, let&amp;rsquo;s say you live in Sydney, Australia, and you executed the same command at the same instant.&lt;/p&gt;
&lt;p&gt;Instead of the above output, you&amp;rsquo;d see the following:&lt;/p&gt;
&lt;div class=&quot;highlight python pycon&quot;&gt;&lt;span class=&quot;repl-toggle&quot; title=&quot;Toggle REPL prompts and output&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;time&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ctime&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ctime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;&amp;#39;Tue Feb 26 12:11:59 2019&amp;#39;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Notice that the &lt;code&gt;day of week&lt;/code&gt;, &lt;code&gt;day of month&lt;/code&gt;, and &lt;code&gt;hour&lt;/code&gt; portions of the timestamp are different than the first example.&lt;/p&gt;
&lt;p&gt;These outputs are different because the timestamp returned by &lt;code&gt;ctime()&lt;/code&gt; depends on your geographical location.&lt;/p&gt;
&lt;div class=&quot;alert alert-primary&quot; role=&quot;alert&quot;&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; While the concept of time zones is relative to your physical location, you can modify this in your computer&amp;rsquo;s settings without actually relocating.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;The representation of time dependent on your physical location is called &lt;strong&gt;local time&lt;/strong&gt; and makes use of a concept called &lt;strong&gt;time zones&lt;/strong&gt;.&lt;/p&gt;
&lt;div class=&quot;alert alert-primary&quot; role=&quot;alert&quot;&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Since local time is related to your locale, timestamps often account for locale-specific details such as the order of the elements in the string and translations of the day and month abbreviations. &lt;code&gt;ctime()&lt;/code&gt; ignores these details.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;Let&amp;rsquo;s dig a little deeper into the notion of time zones so that you can better understand Python time representations.&lt;/p&gt;
&lt;h2 id=&quot;understanding-time-zones&quot;&gt;Understanding Time Zones&lt;/h2&gt;
&lt;p&gt;A time zone is a region of the world that conforms to a standardized time. Time zones are defined by their offset from &lt;a href=&quot;https://en.wikipedia.org/wiki/Coordinated_Universal_Time&quot;&gt;Coordinated Universal Time&lt;/a&gt; (UTC) and, potentially, the inclusion of daylight savings time (which we&amp;rsquo;ll cover in more detail later in this article).&lt;/p&gt;
&lt;div class=&quot;alert alert-primary&quot; role=&quot;alert&quot;&gt;
&lt;p&gt;&lt;strong&gt;Fun Fact:&lt;/strong&gt; If you&amp;rsquo;re a native English speaker, you might be wondering why the abbreviation for &amp;ldquo;Coordinated Universal Time&amp;rdquo; is UTC rather than the more obvious CUT. However, if you&amp;rsquo;re a native French speaker, you would call it &amp;ldquo;Temps Universel Coordonné,&amp;rdquo; which suggests a different abbreviation: TUC.&lt;/p&gt;
&lt;p&gt;Ultimately, the &lt;a href=&quot;https://en.wikipedia.org/wiki/Coordinated_Universal_Time#Etymology&quot;&gt;International Telecommunication Union and the International Astronomical Union compromised on UTC&lt;/a&gt; as the official abbreviation so that, regardless of language, the abbreviation would be the same.&lt;/p&gt;
&lt;/div&gt;
&lt;h3 id=&quot;utc-and-time-zones&quot;&gt;UTC and Time Zones&lt;/h3&gt;
&lt;p&gt;UTC is the time standard against which all the world&amp;rsquo;s timekeeping is synchronized (or coordinated). It is not, itself, a time zone but rather a transcendent standard that defines what time zones are.&lt;/p&gt;
&lt;p&gt;UTC time is precisely measured using &lt;a href=&quot;https://www.merriam-webster.com/dictionary/astronomical%20time&quot;&gt;astronomical time&lt;/a&gt;, referring to the Earth&amp;rsquo;s rotation, and &lt;a href=&quot;https://en.wikipedia.org/wiki/Atomic_clock&quot;&gt;atomic clocks&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Time zones are then defined by their offset from UTC. For example, in North and South America, the Central Time Zone (CT) is behind UTC by five or six hours and, therefore, uses the notation UTC-5:00 or UTC-6:00.&lt;/p&gt;
&lt;p&gt;Sydney, Australia, on the other hand, belongs to the Australian Eastern Time Zone (AET), which is ten or eleven hours ahead of UTC (UTC+10:00 or UTC+11:00).&lt;/p&gt;
&lt;p&gt;This difference (UTC-6:00 to UTC+10:00) is the reason for the variance you observed in the two outputs from &lt;code&gt;ctime()&lt;/code&gt; in the previous examples:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Central Time (CT):&lt;/strong&gt; &lt;code&gt;&#39;Mon Feb 25 19:11:59 2019&#39;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Australian Eastern Time (AET):&lt;/strong&gt; &lt;code&gt;&#39;Tue Feb 26 12:11:59 2019&#39;&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These times are exactly sixteen hours apart, which is consistent with the time zone offsets mentioned above.&lt;/p&gt;
&lt;p&gt;You may be wondering why CT can be either five or six hours behind UTC or why AET can be ten or eleven hours ahead. The reason for this is that some areas around the world, including parts of these time zones, observe daylight savings time.&lt;/p&gt;
&lt;h3 id=&quot;daylight-savings-time&quot;&gt;Daylight Savings Time&lt;/h3&gt;
&lt;p&gt;Summer months generally experience more &lt;a href=&quot;https://sciencing.com/many-hours-daylight-summer-8196183.html&quot;&gt;daylight hours&lt;/a&gt; than winter months. Because of this, some areas observe daylight savings time (DST) during the spring and summer to make better use of those daylight hours.&lt;/p&gt;
&lt;p&gt;For places that observe DST, their clocks will jump ahead one hour at the beginning of spring (effectively losing an hour). Then, in the fall, the clocks will be reset to standard time.&lt;/p&gt;
&lt;p&gt;The letters S and D represent standard time and daylight savings time in time zone notation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Central Standard Time (CST)&lt;/li&gt;
&lt;li&gt;Australian Eastern Daylight Time (AEDT)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;When you represent times as timestamps in local time, it is always important to consider whether DST is applicable or not.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;ctime()&lt;/code&gt; accounts for daylight savings time. So, the output difference listed previously would be more accurate as the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Central Standard Time (CST):&lt;/strong&gt; &lt;code&gt;&#39;Mon Feb 25 19:11:59 2019&#39;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Australian Eastern Daylight Time (AEDT):&lt;/strong&gt; &lt;code&gt;&#39;Tue Feb 26 12:11:59 2019&#39;&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;dealing-with-python-time-using-data-structures&quot;&gt;Dealing With Python Time Using Data Structures&lt;/h2&gt;
&lt;p&gt;Now that you have a firm grasp on many fundamental concepts of time including epochs, time zones, and UTC, let&amp;rsquo;s take a look at more ways to represent time using the Python &lt;code&gt;time&lt;/code&gt; module.&lt;/p&gt;
&lt;h3 id=&quot;python-time-as-a-tuple&quot;&gt;Python Time as a Tuple&lt;/h3&gt;
&lt;p&gt;Instead of using a number to represent Python time, you can use another primitive data structure: a &lt;a href=&quot;https://realpython.com/python-lists-tuples/&quot;&gt;tuple&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The tuple allows you to manage time a little more easily by abstracting some of the data and making it more readable.&lt;/p&gt;
&lt;p&gt;When you represent time as a tuple, each element in your tuple corresponds to a specific element of time:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Year&lt;/li&gt;
&lt;li&gt;Month as an integer, ranging between 1 (January) and 12 (December)&lt;/li&gt;
&lt;li&gt;Day of the month&lt;/li&gt;
&lt;li&gt;Hour as an integer, ranging between 0 (12 A.M.) and 23 (11 P.M.)&lt;/li&gt;
&lt;li&gt;Minute&lt;/li&gt;
&lt;li&gt;Second&lt;/li&gt;
&lt;li&gt;Day of the week as an integer, ranging between 0 (Monday) and 6 (Sunday)&lt;/li&gt;
&lt;li&gt;Day of the year&lt;/li&gt;
&lt;li&gt;Daylight savings time as an integer with the following values:&lt;ul&gt;
&lt;li&gt;&lt;code&gt;1&lt;/code&gt; is daylight savings time.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;0&lt;/code&gt; is standard time.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-1&lt;/code&gt; is unknown.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Using the methods you&amp;rsquo;ve already learned, you can represent the same Python time in two different ways:&lt;/p&gt;
&lt;div class=&quot;highlight python pycon&quot;&gt;&lt;span class=&quot;repl-toggle&quot; title=&quot;Toggle REPL prompts and output&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;time&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ctime&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;t&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;1551186415.360564&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ctime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;&amp;#39;Tue Feb 26 07:06:55 2019&amp;#39;&lt;/span&gt;

&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;time_tuple&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2019&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;26&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;55&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;57&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In this case, both &lt;code&gt;t&lt;/code&gt; and &lt;code&gt;time_tuple&lt;/code&gt; represent the same time, but the tuple provides a more readable interface for working with time components.&lt;/p&gt;
&lt;div class=&quot;alert alert-primary&quot; role=&quot;alert&quot;&gt;
&lt;p&gt;&lt;strong&gt;Technical Detail:&lt;/strong&gt; Actually, if you look at the Python time represented by &lt;code&gt;time_tuple&lt;/code&gt; in seconds (which you&amp;rsquo;ll see how to do later in this article), you&amp;rsquo;ll see that it resolves to &lt;code&gt;1551186415.0&lt;/code&gt; rather than &lt;code&gt;1551186415.360564&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;This is because the tuple doesn&amp;rsquo;t have a way to represent fractional seconds.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;While the tuple provides a more manageable interface for working with Python time, there is an even better object: &lt;code&gt;struct_time&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;python-time-as-an-object&quot;&gt;Python Time as an Object&lt;/h3&gt;
&lt;p&gt;The problem with the tuple construct is that it still looks like a bunch of numbers, even though it&amp;rsquo;s better organized than a single, seconds-based number.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;struct_time&lt;/code&gt; provides a solution to this by utilizing &lt;a href=&quot;https://dbader.org/blog/writing-clean-python-with-namedtuples&quot;&gt;&lt;code&gt;NamedTuple&lt;/code&gt;&lt;/a&gt;, from Python&amp;rsquo;s &lt;code&gt;collections&lt;/code&gt; module, to associate the tuple&amp;rsquo;s sequence of numbers with useful identifiers:&lt;/p&gt;
&lt;div class=&quot;highlight python pycon&quot;&gt;&lt;span class=&quot;repl-toggle&quot; title=&quot;Toggle REPL prompts and output&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;time&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;struct_time&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;time_tuple&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2019&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;26&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;55&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;57&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;time_obj&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;struct_time&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;time_tuple&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;time_obj&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;time.struct_time(tm_year=2019, tm_mon=2, tm_mday=26, tm_hour=7, tm_min=6, tm_sec=55, tm_wday=1, tm_yday=57, tm_isdst=0)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;div class=&quot;alert alert-primary&quot; role=&quot;alert&quot;&gt;
&lt;p&gt;&lt;strong&gt;Technical Detail:&lt;/strong&gt; If you&amp;rsquo;re coming from another language, the terms &lt;code&gt;struct&lt;/code&gt; and &lt;code&gt;object&lt;/code&gt; might be in opposition to one another.&lt;/p&gt;
&lt;p&gt;In Python, there is no data type called &lt;code&gt;struct&lt;/code&gt;. Instead, everything is an object. &lt;/p&gt;
&lt;p&gt;However, the name &lt;code&gt;struct_time&lt;/code&gt; is derived from the &lt;a href=&quot;https://en.cppreference.com/w/c/chrono/tm&quot;&gt;C-based time library&lt;/a&gt; where the data type is actually a &lt;code&gt;struct&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;In fact, Python&amp;rsquo;s &lt;code&gt;time&lt;/code&gt; module, which is &lt;a href=&quot;https://github.com/python/cpython/blob/master/Modules/timemodule.c&quot;&gt;implemented in C&lt;/a&gt;, uses this &lt;code&gt;struct&lt;/code&gt; directly by including the header file &lt;code&gt;times.h&lt;/code&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;Now, you can access specific elements of &lt;code&gt;time_obj&lt;/code&gt;  using the attribute&amp;rsquo;s name rather than an index:&lt;/p&gt;
&lt;div class=&quot;highlight python pycon&quot;&gt;&lt;span class=&quot;repl-toggle&quot; title=&quot;Toggle REPL prompts and output&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;day_of_year&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;time_obj&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;tm_yday&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;day_of_year&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;57&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;day_of_month&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;time_obj&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;tm_mday&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;day_of_month&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;26&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Beyond the readability and usability of &lt;code&gt;struct_time&lt;/code&gt;, it is also important to know because it is the return type of many of the functions in the Python &lt;code&gt;time&lt;/code&gt; module.&lt;/p&gt;
&lt;h2 id=&quot;converting-python-time-in-seconds-to-an-object&quot;&gt;Converting Python Time in Seconds to an Object&lt;/h2&gt;
&lt;p&gt;Now that you&amp;rsquo;ve seen the three primary ways of working with Python time, you&amp;rsquo;ll learn how to convert between the different time data types.&lt;/p&gt;
&lt;p&gt;Converting between time data types is dependent on whether the time is in UTC or local time.&lt;/p&gt;
&lt;h3 id=&quot;coordinated-universal-time-utc&quot;&gt;Coordinated Universal Time (UTC)&lt;/h3&gt;
&lt;p&gt;The epoch uses UTC for its definition rather than a time zone. Therefore, the seconds elapsed since the epoch is not variable depending on your geographical location.&lt;/p&gt;
&lt;p&gt;However, the same cannot be said of &lt;code&gt;struct_time&lt;/code&gt;. The object representation of Python time may or may not take your time zone into account.&lt;/p&gt;
&lt;p&gt;There are two ways to convert a float representing seconds to a &lt;code&gt;struct_time&lt;/code&gt;:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;UTC&lt;/li&gt;
&lt;li&gt;Local time&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;To convert a Python time float to a UTC-based &lt;code&gt;struct_time&lt;/code&gt;, the Python &lt;code&gt;time&lt;/code&gt; module provides a function called &lt;code&gt;gmtime()&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;You&amp;rsquo;ve seen &lt;code&gt;gmtime()&lt;/code&gt; used once before in this article:&lt;/p&gt;
&lt;div class=&quot;highlight python pycon&quot;&gt;&lt;span class=&quot;repl-toggle&quot; title=&quot;Toggle REPL prompts and output&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;time&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gmtime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;time.struct_time(tm_year=1970, tm_mon=1, tm_mday=1, tm_hour=0, tm_min=0, tm_sec=0, tm_wday=3, tm_yday=1, tm_isdst=0)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You used this call to discover your system&amp;rsquo;s epoch. Now, you have a better foundation for understanding what&amp;rsquo;s actually happening here.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;gmtime()&lt;/code&gt; converts the number of elapsed seconds since the epoch to a &lt;code&gt;struct_time&lt;/code&gt; in UTC. In this case, you&amp;rsquo;ve passed &lt;code&gt;0&lt;/code&gt; as the number of seconds, meaning you&amp;rsquo;re trying to find the epoch, itself, in UTC.&lt;/p&gt;
&lt;div class=&quot;alert alert-primary&quot; role=&quot;alert&quot;&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Notice the attribute &lt;code&gt;tm_isdst&lt;/code&gt; is set to &lt;code&gt;0&lt;/code&gt;. This attribute represents whether the time zone is using daylight savings time. UTC never subscribes to DST, so that flag will always be &lt;code&gt;0&lt;/code&gt; when using &lt;code&gt;gmtime()&lt;/code&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;As you saw before, &lt;code&gt;struct_time&lt;/code&gt; cannot represent fractional seconds, so &lt;code&gt;gmtime()&lt;/code&gt; ignores the fractional seconds in the argument:&lt;/p&gt;
&lt;div class=&quot;highlight python pycon&quot;&gt;&lt;span class=&quot;repl-toggle&quot; title=&quot;Toggle REPL prompts and output&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;time&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gmtime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;1.99&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;time.struct_time(tm_year=1970, tm_mon=1, tm_mday=1, tm_hour=0, tm_min=0, tm_sec=1, tm_wday=3, tm_yday=1, tm_isdst=0)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Notice that even though the number of seconds you passed was very close to &lt;code&gt;2&lt;/code&gt;, the &lt;code&gt;.99&lt;/code&gt; fractional seconds were simply ignored, as shown by &lt;code&gt;tm_sec=1&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;secs&lt;/code&gt; parameter for &lt;code&gt;gmtime()&lt;/code&gt; is optional, meaning you can call &lt;code&gt;gmtime()&lt;/code&gt; with no arguments. Doing so will provide the current time in UTC:&lt;/p&gt;
&lt;div class=&quot;highlight python pycon&quot;&gt;&lt;span class=&quot;repl-toggle&quot; title=&quot;Toggle REPL prompts and output&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;time&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gmtime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;time.struct_time(tm_year=2019, tm_mon=2, tm_mday=28, tm_hour=12, tm_min=57, tm_sec=24, tm_wday=3, tm_yday=59, tm_isdst=0)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Interestingly, there is no inverse for this function within &lt;code&gt;time&lt;/code&gt;. Instead, you&amp;rsquo;ll have to look in Python&amp;rsquo;s &lt;code&gt;calendar&lt;/code&gt; module for a function named &lt;code&gt;timegm()&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight python pycon&quot;&gt;&lt;span class=&quot;repl-toggle&quot; title=&quot;Toggle REPL prompts and output&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;calendar&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;time&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gmtime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;time.struct_time(tm_year=2019, tm_mon=2, tm_mday=28, tm_hour=13, tm_min=23, tm_sec=12, tm_wday=3, tm_yday=59, tm_isdst=0)&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;calendar&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;timegm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gmtime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;1551360204&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;code&gt;timegm()&lt;/code&gt; takes a tuple (or &lt;code&gt;struct_time&lt;/code&gt;, since it is a subclass of tuple) and returns the corresponding number of seconds since the epoch.&lt;/p&gt;
&lt;div class=&quot;alert alert-primary&quot; role=&quot;alert&quot;&gt;
&lt;p&gt;&lt;strong&gt;Historical Context:&lt;/strong&gt; If you&amp;rsquo;re interested in why &lt;code&gt;timegm()&lt;/code&gt; is not in &lt;code&gt;time&lt;/code&gt;, you can view the discussion in &lt;a href=&quot;https://bugs.python.org/issue6280&quot;&gt;Python Issue 6280&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In short, it was originally added to &lt;code&gt;calendar&lt;/code&gt; because &lt;code&gt;time&lt;/code&gt; closely follows C&amp;rsquo;s time library (defined in &lt;code&gt;time.h&lt;/code&gt;), which contains no matching function. The above-mentioned issue proposed the idea of moving or copying &lt;code&gt;timegm()&lt;/code&gt; into &lt;code&gt;time&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;However, with advances to the &lt;code&gt;datetime&lt;/code&gt; library, inconsistencies in the patched implementation of &lt;code&gt;time.timegm()&lt;/code&gt;, and a question of how to then handle &lt;code&gt;calendar.timegm()&lt;/code&gt;, the maintainers declined the patch, encouraging the use of &lt;code&gt;datetime&lt;/code&gt; instead.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;Working with UTC is valuable in programming because it&amp;rsquo;s a standard. You don&amp;rsquo;t have to worry about DST, time zone, or locale information.&lt;/p&gt;
&lt;p&gt;That said, there are plenty of cases when you&amp;rsquo;d want to use local time. Next, you&amp;rsquo;ll see how to convert from seconds to local time so that you can do just that.&lt;/p&gt;
&lt;h3 id=&quot;local-time&quot;&gt;Local Time&lt;/h3&gt;
&lt;p&gt;In your application, you may need to work with local time rather than UTC. Python&amp;rsquo;s &lt;code&gt;time&lt;/code&gt; module provides a function for getting local time from the number of seconds elapsed since the epoch called &lt;code&gt;localtime()&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The signature of &lt;code&gt;localtime()&lt;/code&gt; is similar to &lt;code&gt;gmtime()&lt;/code&gt; in that it takes an optional &lt;code&gt;secs&lt;/code&gt; argument, which it uses to build a &lt;code&gt;struct_time&lt;/code&gt; using your local time zone:&lt;/p&gt;
&lt;div class=&quot;highlight python pycon&quot;&gt;&lt;span class=&quot;repl-toggle&quot; title=&quot;Toggle REPL prompts and output&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;time&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;1551448206.86196&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;localtime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;1551448206.86196&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;time.struct_time(tm_year=2019, tm_mon=3, tm_mday=1, tm_hour=7, tm_min=50, tm_sec=6, tm_wday=4, tm_yday=60, tm_isdst=0)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Notice that &lt;code&gt;tm_isdst=0&lt;/code&gt;. Since DST matters with local time, &lt;code&gt;tm_isdst&lt;/code&gt; will change between &lt;code&gt;0&lt;/code&gt; and &lt;code&gt;1&lt;/code&gt; depending on whether or not DST is applicable for the given time. Since &lt;code&gt;tm_isdst=0&lt;/code&gt;, DST is not applicable for March 1, 2019.&lt;/p&gt;
&lt;p&gt;In the United States in 2019, daylight savings time begins on March 10. So, to test if the DST flag will change correctly, you need to add 9 days&amp;rsquo; worth of seconds to the &lt;code&gt;secs&lt;/code&gt; argument.&lt;/p&gt;
&lt;p&gt;To compute this, you take the number of seconds in a day (86,400) and multiply that by 9 days:&lt;/p&gt;
&lt;div class=&quot;highlight python pycon&quot;&gt;&lt;span class=&quot;repl-toggle&quot; title=&quot;Toggle REPL prompts and output&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new_secs&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;1551448206.86196&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;86400&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;9&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;localtime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new_secs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;time.struct_time(tm_year=2019, tm_mon=3, tm_mday=10, tm_hour=8, tm_min=50, tm_sec=6, tm_wday=6, tm_yday=69, tm_isdst=1)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now, you&amp;rsquo;ll see that the &lt;code&gt;struct_time&lt;/code&gt; shows the date to be March 10, 2019 with &lt;code&gt;tm_isdst=1&lt;/code&gt;. Also, notice that &lt;code&gt;tm_hour&lt;/code&gt; has also jumped ahead, to &lt;code&gt;8&lt;/code&gt; instead of &lt;code&gt;7&lt;/code&gt; in the previous example, because of daylight savings time.&lt;/p&gt;
&lt;p&gt;Since Python 3.3, &lt;code&gt;struct_time&lt;/code&gt; has also included two attributes that are useful in determining the time zone of the &lt;code&gt;struct_time&lt;/code&gt;:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;tm_zone&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;tm_gmtoff&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;At first, these attributes were platform dependent, but they have been available on all platforms since Python 3.6.&lt;/p&gt;
&lt;p&gt;First, &lt;code&gt;tm_zone&lt;/code&gt; stores the local time zone:&lt;/p&gt;
&lt;div class=&quot;highlight python pycon&quot;&gt;&lt;span class=&quot;repl-toggle&quot; title=&quot;Toggle REPL prompts and output&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;time&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;current_local&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;localtime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;current_local&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;tm_zone&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;&amp;#39;CST&amp;#39;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Here, you can see that &lt;code&gt;localtime()&lt;/code&gt; returns a &lt;code&gt;struct_time&lt;/code&gt; with the time zone set to &lt;code&gt;CST&lt;/code&gt; (Central Standard Time).&lt;/p&gt;
&lt;p&gt;As you saw before, you can also tell the time zone based on two pieces of information, the UTC offset and DST (if applicable):&lt;/p&gt;
&lt;div class=&quot;highlight python pycon&quot;&gt;&lt;span class=&quot;repl-toggle&quot; title=&quot;Toggle REPL prompts and output&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;time&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;current_local&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;localtime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;current_local&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;tm_gmtoff&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;-21600&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;current_local&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;tm_isdst&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;0&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In this case, you can see that &lt;code&gt;current_local&lt;/code&gt; is &lt;code&gt;21600&lt;/code&gt; seconds behind GMT, which stands for Greenwich Mean Time. GMT is the time zone with no UTC offset: UTC±00:00.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;21600&lt;/code&gt; seconds divided by seconds per hour (3,600) means that &lt;code&gt;current_local&lt;/code&gt; time is &lt;code&gt;GMT-06:00&lt;/code&gt; (or &lt;code&gt;UTC-06:00&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;You can use the GMT offset plus the DST status to deduce that &lt;code&gt;current_local&lt;/code&gt; is &lt;code&gt;UTC-06:00&lt;/code&gt; at standard time, which corresponds to the Central standard time zone.&lt;/p&gt;
&lt;p&gt;Like &lt;code&gt;gmtime()&lt;/code&gt;, you can ignore the &lt;code&gt;secs&lt;/code&gt; argument when calling &lt;code&gt;localtime()&lt;/code&gt;, and it will return the current local time in a &lt;code&gt;struct_time&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight python pycon&quot;&gt;&lt;span class=&quot;repl-toggle&quot; title=&quot;Toggle REPL prompts and output&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;time&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;localtime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;time.struct_time(tm_year=2019, tm_mon=3, tm_mday=1, tm_hour=8, tm_min=34, tm_sec=28, tm_wday=4, tm_yday=60, tm_isdst=0)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Unlike &lt;code&gt;gmtime()&lt;/code&gt;, the inverse function of &lt;code&gt;localtime()&lt;/code&gt; does exist in the Python &lt;code&gt;time&lt;/code&gt; module. Let&amp;rsquo;s take a look at how that works.&lt;/p&gt;
&lt;h2 id=&quot;converting-a-local-time-object-to-seconds&quot;&gt;Converting a Local Time Object to Seconds&lt;/h2&gt;
&lt;p&gt;You&amp;rsquo;ve already seen how to convert a UTC time object to seconds using &lt;code&gt;calendar.timegm()&lt;/code&gt;. To convert local time to seconds, you&amp;rsquo;ll use &lt;code&gt;mktime()&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;mktime()&lt;/code&gt; requires you to pass a parameter called &lt;code&gt;t&lt;/code&gt; that takes the form of either a normal 9-tuple or a &lt;code&gt;struct_time&lt;/code&gt; object representing local time:&lt;/p&gt;
&lt;div class=&quot;highlight python pycon&quot;&gt;&lt;span class=&quot;repl-toggle&quot; title=&quot;Toggle REPL prompts and output&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;time&lt;/span&gt;

&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;time_tuple&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2019&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;50&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;69&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mktime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;time_tuple&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;1552225806.0&lt;/span&gt;

&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;time_struct&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;struct_time&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;time_tuple&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mktime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;time_struct&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;1552225806.0&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;It&amp;rsquo;s important to keep in mind that &lt;code&gt;t&lt;/code&gt; must be a tuple representing local time, not UTC:&lt;/p&gt;
&lt;div class=&quot;highlight python pycon&quot;&gt;&lt;span class=&quot;repl-toggle&quot; title=&quot;Toggle REPL prompts and output&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;time&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;gmtime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mktime&lt;/span&gt;

&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;# 1&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;current_utc&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gmtime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;current_utc&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;time.struct_time(tm_year=2019, tm_mon=3, tm_mday=1, tm_hour=14, tm_min=51, tm_sec=19, tm_wday=4, tm_yday=60, tm_isdst=0)&lt;/span&gt;

&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;# 2&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;current_utc_secs&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mktime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;current_utc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;current_utc_secs&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;1551473479.0&lt;/span&gt;

&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;# 3&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gmtime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;current_utc_secs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;time.struct_time(tm_year=2019, tm_mon=3, tm_mday=1, tm_hour=20, tm_min=51, tm_sec=19, tm_wday=4, tm_yday=60, tm_isdst=0)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;div class=&quot;alert alert-primary&quot; role=&quot;alert&quot;&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; For this example, assume that the local time is &lt;code&gt;March 1, 2019 08:51:19 CST&lt;/code&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;This example shows why it&amp;rsquo;s important to use &lt;code&gt;mktime()&lt;/code&gt; with local time, rather than UTC:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;gmtime()&lt;/code&gt;&lt;/strong&gt; with no argument returns a &lt;code&gt;struct_time&lt;/code&gt; using UTC. &lt;code&gt;current_utc&lt;/code&gt; shows &lt;code&gt;March 1, 2019 14:51:19 UTC&lt;/code&gt;. This is accurate because &lt;code&gt;CST is UTC-06:00&lt;/code&gt;, so UTC should be 6 hours ahead of local time.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;mktime()&lt;/code&gt;&lt;/strong&gt; tries to return the number of seconds, expecting local time, but you passed &lt;code&gt;current_utc&lt;/code&gt; instead. So, instead of understanding that &lt;code&gt;current_utc&lt;/code&gt; is UTC time, it assumes you meant &lt;code&gt;March 1, 2019 14:51:19 CST&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;gmtime()&lt;/code&gt;&lt;/strong&gt; is then used to convert those seconds back into UTC, which results in an inconsistency. The time is now &lt;code&gt;March 1, 2019 20:51:19 UTC&lt;/code&gt;. The reason for this discrepancy is the fact that &lt;code&gt;mktime()&lt;/code&gt; expected local time. So, the conversion back to UTC adds &lt;em&gt;another&lt;/em&gt; 6 hours to local time.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Working with time zones is notoriously difficult, so it&amp;rsquo;s important to set yourself up for success by understanding the differences between UTC and local time and the Python time functions that deal with each.&lt;/p&gt;
&lt;h2 id=&quot;converting-a-python-time-object-to-a-string&quot;&gt;Converting a Python Time Object to a String&lt;/h2&gt;
&lt;p&gt;While working with tuples is fun and all, sometimes it&amp;rsquo;s best to work with strings.&lt;/p&gt;
&lt;p&gt;String representations of time, also known as timestamps, help make times more readable and can be especially useful for building intuitive user interfaces.&lt;/p&gt;
&lt;p&gt;There are two Python &lt;code&gt;time&lt;/code&gt; functions that you use for converting a &lt;code&gt;time.struct_time&lt;/code&gt; object to a string:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;asctime()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;strftime()&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;You&amp;rsquo;ll begin by learning about&lt;code&gt;asctime()&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;asctime&quot;&gt;&lt;code&gt;asctime()&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;You use &lt;code&gt;asctime()&lt;/code&gt; for converting a time tuple or &lt;code&gt;struct_time&lt;/code&gt;  to a timestamp:&lt;/p&gt;
&lt;div class=&quot;highlight python pycon&quot;&gt;&lt;span class=&quot;repl-toggle&quot; title=&quot;Toggle REPL prompts and output&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;time&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;asctime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gmtime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;&amp;#39;Fri Mar  1 18:42:08 2019&amp;#39;&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;asctime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;localtime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;&amp;#39;Fri Mar  1 12:42:15 2019&amp;#39;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Both &lt;code&gt;gmtime()&lt;/code&gt; and &lt;code&gt;localtime()&lt;/code&gt; return &lt;code&gt;struct_time&lt;/code&gt; instances, for UTC and local time respectively.&lt;/p&gt;
&lt;p&gt;You can use &lt;code&gt;asctime()&lt;/code&gt; to convert either &lt;code&gt;struct_time&lt;/code&gt; to a timestamp. &lt;code&gt;asctime()&lt;/code&gt; works similarly to &lt;code&gt;ctime()&lt;/code&gt;, which you learned about earlier in this article, except instead of passing a floating point number, you pass a tuple. Even the timestamp format is the same between the two functions.&lt;/p&gt;
&lt;p&gt;As with &lt;code&gt;ctime()&lt;/code&gt;, the parameter for &lt;code&gt;asctime()&lt;/code&gt; is optional. If you do not pass a time object to &lt;code&gt;asctime()&lt;/code&gt;, then it will use the current local time:&lt;/p&gt;
&lt;div class=&quot;highlight python pycon&quot;&gt;&lt;span class=&quot;repl-toggle&quot; title=&quot;Toggle REPL prompts and output&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;time&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;asctime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;&amp;#39;Fri Mar  1 12:56:07 2019&amp;#39;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;As with &lt;code&gt;ctime()&lt;/code&gt;, it also ignores locale information.&lt;/p&gt;
&lt;p&gt;One of the biggest drawbacks of &lt;code&gt;asctime()&lt;/code&gt; is its format inflexibility. &lt;code&gt;strftime()&lt;/code&gt; solves this problem by allowing you to format your timestamps.&lt;/p&gt;
&lt;h3 id=&quot;strftime&quot;&gt;&lt;code&gt;strftime()&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;You may find yourself in a position where the string format from &lt;code&gt;ctime()&lt;/code&gt; and &lt;code&gt;asctime()&lt;/code&gt; isn&amp;rsquo;t satisfactory for your application. Instead, you may want to format your strings in a way that&amp;rsquo;s more meaningful to your users.&lt;/p&gt;
&lt;p&gt;One example of this is if you would like to display your time in a string that takes locale information into account.&lt;/p&gt;
&lt;p&gt;To format strings, given a &lt;code&gt;struct_time&lt;/code&gt; or Python time tuple,  you use &lt;code&gt;strftime()&lt;/code&gt;, which stands for &amp;ldquo;string &lt;strong&gt;format&lt;/strong&gt; time.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;strftime()&lt;/code&gt; takes two arguments:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;format&lt;/code&gt;&lt;/strong&gt; specifies the order and form of the time elements in your string.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;t&lt;/code&gt;&lt;/strong&gt; is an optional time tuple.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;To format a string, you use &lt;strong&gt;directives&lt;/strong&gt;. Directives are character sequences that begin with a &lt;code&gt;%&lt;/code&gt; that specify a particular time element, such as:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;%d&lt;/code&gt;:&lt;/strong&gt; Day of the month&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;%m&lt;/code&gt;:&lt;/strong&gt; Month of the year&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;%Y&lt;/code&gt;:&lt;/strong&gt; Year&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For example, you can output the date in your local time using the &lt;a href=&quot;https://en.wikipedia.org/wiki/ISO_8601&quot;&gt;ISO 8601&lt;/a&gt; standard like this:&lt;/p&gt;
&lt;div class=&quot;highlight python pycon&quot;&gt;&lt;span class=&quot;repl-toggle&quot; title=&quot;Toggle REPL prompts and output&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;time&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;strftime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;%Y-%m-&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%d&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;localtime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;&amp;#39;2019-03-01&amp;#39;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;div class=&quot;alert alert-primary&quot; role=&quot;alert&quot;&gt;
&lt;p&gt;&lt;strong&gt;Further Reading:&lt;/strong&gt; While representing dates using Python time is completely valid and acceptable, you should also consider using Python&amp;rsquo;s &lt;code&gt;datetime&lt;/code&gt; module, which provides shortcuts and a more robust framework for working with dates and times together.&lt;/p&gt;
&lt;p&gt;For example, you can simplify outputting a date in the ISO 8601 format using &lt;code&gt;datetime&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight python pycon&quot;&gt;&lt;span class=&quot;repl-toggle&quot; title=&quot;Toggle REPL prompts and output&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;datetime&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;date&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;date&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;year&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2019&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;month&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;day&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;isoformat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;&amp;#39;2019-03-01&amp;#39;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;/div&gt;
&lt;p&gt;As you saw before, a great benefit of using &lt;code&gt;strftime()&lt;/code&gt; over &lt;code&gt;asctime()&lt;/code&gt; is its ability to render timestamps that make use of locale-specific information.&lt;/p&gt;
&lt;p&gt;For example, if you want to represent the date and time in a locale-sensitive way, you can&amp;rsquo;t use &lt;code&gt;asctime()&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight python pycon&quot;&gt;&lt;span class=&quot;repl-toggle&quot; title=&quot;Toggle REPL prompts and output&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;time&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;asctime&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;asctime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;&amp;#39;Sat Mar  2 15:21:14 2019&amp;#39;&lt;/span&gt;

&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;locale&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;locale&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;setlocale&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;locale&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;LC_TIME&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;zh_HK&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# Chinese - Hong Kong&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;&amp;#39;zh_HK&amp;#39;&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;asctime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;&amp;#39;Sat Mar  2 15:58:49 2019&amp;#39;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Notice that even after programmatically changing your locale, &lt;code&gt;asctime()&lt;/code&gt; still returns the date and time in the same format as before.&lt;/p&gt;
&lt;div class=&quot;alert alert-primary&quot; role=&quot;alert&quot;&gt;
&lt;p&gt;&lt;strong&gt;Technical Detail:&lt;/strong&gt; &lt;code&gt;LC_TIME&lt;/code&gt; is the locale category for date and time formatting. The &lt;code&gt;locale&lt;/code&gt; argument &lt;code&gt;&#39;zh_HK&#39;&lt;/code&gt; may be different, depending on your system.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;When you use &lt;code&gt;strftime()&lt;/code&gt;, however, you&amp;rsquo;ll see that it accounts for locale:&lt;/p&gt;
&lt;div class=&quot;highlight python pycon&quot;&gt;&lt;span class=&quot;repl-toggle&quot; title=&quot;Toggle REPL prompts and output&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;time&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;strftime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;localtime&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;strftime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%c&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;localtime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;&amp;#39;Sat Mar  2 15:23:20 2019&amp;#39;&lt;/span&gt;

&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;locale&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;locale&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;setlocale&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;locale&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;LC_TIME&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;zh_HK&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# Chinese - Hong Kong&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;&amp;#39;zh_HK&amp;#39;&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;strftime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%c&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;localtime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;&amp;#39;六  3/ 2 15:58:12 2019&amp;#39; 2019&amp;#39;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Here, you have successfully utilized the locale information because you used &lt;code&gt;strftime()&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;alert alert-primary&quot; role=&quot;alert&quot;&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; &lt;code&gt;%c&lt;/code&gt; is the directive for locale-appropriate date and time.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;If the time tuple is not passed to the parameter &lt;code&gt;t&lt;/code&gt;, then &lt;code&gt;strftime()&lt;/code&gt; will use the result of &lt;code&gt;localtime()&lt;/code&gt; by default. So, you could simplify the examples above by removing the optional second argument:&lt;/p&gt;
&lt;div class=&quot;highlight python pycon&quot;&gt;&lt;span class=&quot;repl-toggle&quot; title=&quot;Toggle REPL prompts and output&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;time&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;strftime&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;strftime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;The current local datetime is: &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%c&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;&amp;#39;The current local datetime is: Fri Mar  1 23:18:32 2019&amp;#39;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Here, you&amp;rsquo;ve used the default time instead of passing your own as an argument. Also, notice that the &lt;code&gt;format&lt;/code&gt; argument can consist of text other than formatting directives.&lt;/p&gt;
&lt;div class=&quot;alert alert-primary&quot; role=&quot;alert&quot;&gt;
&lt;p&gt;&lt;strong&gt;Further Reading:&lt;/strong&gt; Check out this thorough &lt;a href=&quot;https://docs.python.org/3/library/time.html#time.strftime&quot;&gt;list of directives&lt;/a&gt; available to &lt;code&gt;strftime()&lt;/code&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;The Python &lt;code&gt;time&lt;/code&gt; module also includes the inverse operation of converting a timestamp back into a &lt;code&gt;struct_time&lt;/code&gt; object.&lt;/p&gt;
&lt;h2 id=&quot;converting-a-python-time-string-to-an-object&quot;&gt;Converting a Python Time String to an Object&lt;/h2&gt;
&lt;p&gt;When you&amp;rsquo;re working with date and time related strings, it can be very valuable to convert the timestamp to a time object.&lt;/p&gt;
&lt;p&gt;To convert a time string to a &lt;code&gt;struct_time&lt;/code&gt;, you use &lt;code&gt;strptime()&lt;/code&gt;, which stands for &amp;ldquo;string &lt;strong&gt;parse&lt;/strong&gt; time&amp;rdquo;:&lt;/p&gt;
&lt;div class=&quot;highlight python pycon&quot;&gt;&lt;span class=&quot;repl-toggle&quot; title=&quot;Toggle REPL prompts and output&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;time&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;strptime&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;strptime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;2019-03-01&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;%Y-%m-&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%d&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;time.struct_time(tm_year=2019, tm_mon=3, tm_mday=1, tm_hour=0, tm_min=0, tm_sec=0, tm_wday=4, tm_yday=60, tm_isdst=-1)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The first argument to &lt;code&gt;strptime()&lt;/code&gt; must be the timestamp you wish to convert. The second argument is the &lt;code&gt;format&lt;/code&gt; that the timestamp is in.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;format&lt;/code&gt; parameter is optional and defaults to &lt;code&gt;&#39;%a %b %d %H:%M:%S %Y&#39;&lt;/code&gt;. Therefore, if you have a timestamp in that format, you don&amp;rsquo;t need to pass it as an argument:&lt;/p&gt;
&lt;div class=&quot;highlight python pycon&quot;&gt;&lt;span class=&quot;repl-toggle&quot; title=&quot;Toggle REPL prompts and output&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;strptime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;Fri Mar 01 23:38:40 2019&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;time.struct_time(tm_year=2019, tm_mon=3, tm_mday=1, tm_hour=23, tm_min=38, tm_sec=40, tm_wday=4, tm_yday=60, tm_isdst=-1)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Since a &lt;code&gt;struct_time&lt;/code&gt; has 9 key date and time components, &lt;code&gt;strptime()&lt;/code&gt; must provide reasonable defaults for values for those components it can&amp;rsquo;t parse from &lt;code&gt;string&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;In the previous examples, &lt;code&gt;tm_isdst=-1&lt;/code&gt;. This means that &lt;code&gt;strptime()&lt;/code&gt; can&amp;rsquo;t determine by the timestamp whether it represents daylight savings time or not.&lt;/p&gt;
&lt;p&gt;Now you know how to work with Python times and dates using the &lt;code&gt;time&lt;/code&gt; module in a variety of ways. However, there are other uses for &lt;code&gt;time&lt;/code&gt; outside of simply creating time objects, getting Python time strings, and using seconds elapsed since the epoch.&lt;/p&gt;
&lt;h2 id=&quot;suspending-execution&quot;&gt;Suspending Execution&lt;/h2&gt;
&lt;p&gt;One really useful Python time function is &lt;code&gt;sleep()&lt;/code&gt;, which suspends the thread&amp;rsquo;s execution for a specified amount of time.&lt;/p&gt;
&lt;p&gt;For example, you can suspend your program&amp;rsquo;s execution for 10 seconds like this:&lt;/p&gt;
&lt;div class=&quot;highlight python pycon&quot;&gt;&lt;span class=&quot;repl-toggle&quot; title=&quot;Toggle REPL prompts and output&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;time&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sleep&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;strftime&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;strftime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%c&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;&amp;#39;Fri Mar  1 23:49:26 2019&amp;#39;&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sleep&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;strftime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%c&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;&amp;#39;Fri Mar  1 23:49:36 2019&amp;#39;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Your program will print the first formatted &lt;code&gt;datetime&lt;/code&gt; string, then pause for 10 seconds, and finally print the second formatted &lt;code&gt;datetime&lt;/code&gt; string.&lt;/p&gt;
&lt;p&gt;You can also pass fractional seconds to &lt;code&gt;sleep()&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight python pycon&quot;&gt;&lt;span class=&quot;repl-toggle&quot; title=&quot;Toggle REPL prompts and output&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;time&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sleep&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sleep&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;code&gt;sleep()&lt;/code&gt; is useful for testing or making your program wait for any reason, but you must be careful not to halt your production code unless you have good reason to do so.&lt;/p&gt;
&lt;p&gt;Before Python 3.5, a signal sent to your process could interrupt &lt;code&gt;sleep()&lt;/code&gt;. However, in 3.5 and later, &lt;code&gt;sleep()&lt;/code&gt; will always suspend execution for at least the amount of specified time, even if the process receives a signal.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;sleep()&lt;/code&gt; is just one Python time function that can help you test your programs and make them more robust.&lt;/p&gt;
&lt;h2 id=&quot;measuring-performance&quot;&gt;Measuring Performance&lt;/h2&gt;
&lt;p&gt;You can use &lt;code&gt;time&lt;/code&gt; to measure the performance of your program.&lt;/p&gt;
&lt;p&gt;The way you do this is to use &lt;code&gt;perf_counter()&lt;/code&gt; which, as the name suggests, provides a performance counter with a high resolution to measure short distances of time.&lt;/p&gt;
&lt;p&gt;To use &lt;code&gt;perf_counter()&lt;/code&gt;, you place a counter before your code begins execution as well as after your code&amp;rsquo;s execution completes:&lt;/p&gt;
&lt;div class=&quot;highlight python pycon&quot;&gt;&lt;span class=&quot;repl-toggle&quot; title=&quot;Toggle REPL prompts and output&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;time&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;perf_counter&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;longrunning_function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;... &lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;range&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;11&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;... &lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sleep&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;**&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;...&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;start&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;perf_counter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;longrunning_function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;end&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;perf_counter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;execution_time&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;end&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;start&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;execution_time&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;8.201258441999926&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;First, &lt;code&gt;start&lt;/code&gt; captures the moment before you call the function. &lt;code&gt;end&lt;/code&gt; captures the moment after the function returns. The function&amp;rsquo;s total execution time took &lt;code&gt;(end - start)&lt;/code&gt; seconds.&lt;/p&gt;
&lt;div class=&quot;alert alert-primary&quot; role=&quot;alert&quot;&gt;
&lt;p&gt;&lt;strong&gt;Technical Detail:&lt;/strong&gt; Python 3.7 introduced &lt;code&gt;perf_counter_ns()&lt;/code&gt;, which works the same as &lt;code&gt;perf_counter()&lt;/code&gt;, but uses nanoseconds instead of seconds.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;&lt;code&gt;perf_counter()&lt;/code&gt; (or &lt;code&gt;perf_counter_ns()&lt;/code&gt;) is the most precise way to measure the performance of your code using one execution. However, if you&amp;rsquo;re trying to accurately gauge the performance of a code snippet, I recommend using the &lt;a href=&quot;https://docs.python.org/3/library/timeit.html&quot;&gt;Python &lt;code&gt;timeit&lt;/code&gt;&lt;/a&gt; module.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;timeit&lt;/code&gt; specializes in running code many times to get a more accurate performance analysis and helps you to avoid oversimplifying your time measurement as well as other common pitfalls.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Congratulations! You now have a great foundation for working with dates and times in Python.&lt;/p&gt;
&lt;p&gt;Now, you&amp;rsquo;re able to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Use a floating point number, representing seconds elapsed since the epoch, to deal with time&lt;/li&gt;
&lt;li&gt;Manage time using tuples and &lt;code&gt;struct_time&lt;/code&gt; objects&lt;/li&gt;
&lt;li&gt;Convert between seconds, tuples, and timestamp strings&lt;/li&gt;
&lt;li&gt;Suspend the execution of a Python thread&lt;/li&gt;
&lt;li&gt;Measure performance using &lt;code&gt;perf_counter()&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;On top of all that, you&amp;rsquo;ve learned some fundamental concepts surrounding date and time, such as:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Epochs&lt;/li&gt;
&lt;li&gt;UTC&lt;/li&gt;
&lt;li&gt;Time zones&lt;/li&gt;
&lt;li&gt;Daylight savings time&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now, it&amp;rsquo;s time for you to apply your newfound knowledge of Python time in your real world applications!&lt;/p&gt;
&lt;h2 id=&quot;further-reading&quot;&gt;Further Reading&lt;/h2&gt;
&lt;p&gt;If you want to continue learning more about using dates and times in Python, take a look at the following modules:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://docs.python.org/3/library/datetime.html&quot;&gt;&lt;code&gt;datetime&lt;/code&gt;&lt;/a&gt;:&lt;/strong&gt; A more robust date and time module in Python&amp;rsquo;s standard library&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://docs.python.org/3/library/timeit.html&quot;&gt;&lt;code&gt;timeit&lt;/code&gt;&lt;/a&gt;:&lt;/strong&gt; A module for measuring the performance of code snippets&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;http://docs.astropy.org/en/stable/time/&quot;&gt;&lt;code&gt;astropy&lt;/code&gt;&lt;/a&gt;:&lt;/strong&gt; Higher precision datetimes used in astronomy&lt;/li&gt;
&lt;/ul&gt;
        &lt;hr /&gt;
        &lt;p&gt;&lt;em&gt;[ Improve Your Python With 🐍 Python Tricks 💌 – Get a short &amp;amp; sweet Python Trick delivered to your inbox every couple of days. &lt;a href=&quot;https://realpython.com/python-tricks/?utm_source=realpython&amp;amp;utm_medium=rss&amp;amp;utm_campaign=footer&quot;&gt;&amp;gt;&amp;gt; Click here to learn more and see examples&lt;/a&gt; ]&lt;/em&gt;&lt;/p&gt;
      </content>
    </entry>
  
    <entry>
      <title>Immutability in Python</title>
      <id>https://realpython.com/courses/immutability-python/</id>
      <link href="https://realpython.com/courses/immutability-python/"/>
      <updated>2019-04-18T14:00:00+00:00</updated>
      <summary>In Python, immutable vs mutable data types and objects types can cause some confusion—and weird bugs. With this course you&#39;ll see what the difference between mutable and immutable data types is in Python, and how you can use it to your advantage in your own programs.</summary>
      <content type="html">
        &lt;p&gt;In Python, immutable vs mutable data types and objects types can cause some confusion—and weird bugs. With this video course you&amp;rsquo;ll see what the difference between mutable and immutable data types is in Python, and how you can use it to your advantage in your own programs.&lt;/p&gt;
&lt;p&gt;You&amp;rsquo;ll also see how to deal with a language quirk in Python that allows objects referenced by immutable types to me modified. Python&amp;rsquo;s definition of &amp;ldquo;immutable&amp;rdquo; can be a bit misleading.&lt;/p&gt;
&lt;p&gt;Basically, the promise of &amp;ldquo;immutability&amp;rdquo; on tuples is only partly true. The tuple itself cannot be modified, but objects referenced by the tuple can be. This is sometimes called &amp;ldquo;non-transitive immutability.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;If the tuple has an immutable field like a string for example, then it cannot be modified. A mutable field like a list however, can be edited, even if it&amp;rsquo;s embedded in the &amp;ldquo;immutable&amp;rdquo; tuple.&lt;/p&gt;
&lt;p&gt;When the Python documentation refers to an object as being &amp;ldquo;immutable&amp;rdquo; they mean the behavior above observed. Other immutable types in Python behave the same way, e.g. namedtuples or frozensets.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;ve ever encountered the following exception and now you want to know why, this is the video course for you:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;TypeError: &amp;#39;tuple&amp;#39; object does not support item assignment
&lt;/pre&gt;&lt;/div&gt;
        &lt;hr /&gt;
        &lt;p&gt;&lt;em&gt;[ Improve Your Python With 🐍 Python Tricks 💌 – Get a short &amp;amp; sweet Python Trick delivered to your inbox every couple of days. &lt;a href=&quot;https://realpython.com/python-tricks/?utm_source=realpython&amp;amp;utm_medium=rss&amp;amp;utm_campaign=footer&quot;&gt;&amp;gt;&amp;gt; Click here to learn more and see examples&lt;/a&gt; ]&lt;/em&gt;&lt;/p&gt;
      </content>
    </entry>
  
    <entry>
      <title>How to Work With a PDF in Python</title>
      <id>https://realpython.com/pdf-python/</id>
      <link href="https://realpython.com/pdf-python/"/>
      <updated>2019-04-17T14:00:00+00:00</updated>
      <summary>In this step-by-step tutorial, you&#39;ll learn how to work with a PDF in Python. You&#39;ll see how to extract metadata from preexisting PDFs . You&#39;ll also learn how to merge, split, watermark, and rotate pages in PDFs using Python and PyPDF2.</summary>
      <content type="html">
        &lt;p&gt;The Portable Document Format or PDF is a file format that can be used to present and exchange documents reliably across operating systems. While the PDF was originally invented by Adobe, it is now an &lt;a href=&quot;https://www.iso.org/standard/51502.html&quot;&gt;open standard&lt;/a&gt; that is maintained by the International Organization for Standardization (ISO). You can work with a preexisting PDF in Python by using the &lt;strong&gt;&lt;code&gt;PyPDF2&lt;/code&gt;&lt;/strong&gt; package.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;PyPDF2&lt;/code&gt; is a &lt;a href=&quot;https://stackoverflow.com/questions/45976946/what-is-pure-python&quot;&gt;pure-Python&lt;/a&gt; package that you can use for many different types of PDF operations.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;By the end of this article, you&amp;rsquo;ll know how to do the following:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Extract document information from a PDF in Python&lt;/li&gt;
&lt;li&gt;Rotate pages&lt;/li&gt;
&lt;li&gt;Merge PDFs&lt;/li&gt;
&lt;li&gt;Split PDFs&lt;/li&gt;
&lt;li&gt;Add watermarks&lt;/li&gt;
&lt;li&gt;Encrypt a PDF&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Let&amp;rsquo;s get started!&lt;/p&gt;
&lt;div class=&quot;alert alert-warning&quot; role=&quot;alert&quot;&gt;&lt;p&gt;&lt;strong&gt;Free Bonus:&lt;/strong&gt; &lt;a href=&quot;&quot; class=&quot;alert-link&quot; data-toggle=&quot;modal&quot; data-target=&quot;#modal-python-tricks-sample&quot; data-focus=&quot;false&quot;&gt;Click here to get access to a chapter from Python Tricks: The Book&lt;/a&gt; that shows you Python&#39;s best practices with simple examples you can apply instantly to write more beautiful + Pythonic code.&lt;/p&gt;&lt;/div&gt;

&lt;h2 id=&quot;history-of-pypdf-pypdf2-and-pypdf4&quot;&gt;History of &lt;code&gt;pyPdf&lt;/code&gt;, &lt;code&gt;PyPDF2&lt;/code&gt;, and &lt;code&gt;PyPDF4&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;The original &lt;a href=&quot;https://pypi.org/project/pyPdf/&quot;&gt;&lt;code&gt;pyPdf&lt;/code&gt;&lt;/a&gt; package was released way back in 2005. The last official release of &lt;code&gt;pyPdf&lt;/code&gt; was in 2010. After a lapse of around a year, a company called &lt;a href=&quot;http://phaseit.net/&quot;&gt;Phasit&lt;/a&gt; sponsored a fork of &lt;code&gt;pyPdf&lt;/code&gt; called &lt;a href=&quot;https://pythonhosted.org/PyPDF2/&quot;&gt;&lt;code&gt;PyPDF2&lt;/code&gt;&lt;/a&gt;. The code was written to be backwards compatible with the original and worked quite well for several years, with its last release being in 2016. &lt;/p&gt;
&lt;p&gt;There was a brief series of releases of a package called &lt;a href=&quot;https://pypi.org/project/PyPDF3/&quot;&gt;&lt;code&gt;PyPDF3&lt;/code&gt;&lt;/a&gt;, and then the project was renamed to &lt;a href=&quot;https://pypi.org/project/PyPDF2/&quot;&gt;&lt;code&gt;PyPDF4&lt;/code&gt;&lt;/a&gt;. All of these projects do pretty much the same thing, but the biggest difference between &lt;code&gt;pyPdf&lt;/code&gt; and PyPDF2+ is that the latter versions added Python 3 support. There is a different Python 3 fork of the original &lt;a href=&quot;http://github.com/mfenniak/pyPdf/tree/py3&quot;&gt;&lt;code&gt;pyPdf&lt;/code&gt; for Python 3&lt;/a&gt;, but that one has not been maintained for many years.&lt;/p&gt;
&lt;p&gt;While &lt;code&gt;PyPDF2&lt;/code&gt; was recently abandoned, the new &lt;a href=&quot;https://github.com/claird/PyPDF4&quot;&gt;&lt;code&gt;PyPDF4&lt;/code&gt;&lt;/a&gt; does not have full backwards compatibility with &lt;code&gt;PyPDF2&lt;/code&gt;. Most of the examples in this article will work perfectly fine with &lt;code&gt;PyPDF4&lt;/code&gt;, but there are some that cannot, which is why &lt;code&gt;PyPDF4&lt;/code&gt; is not featured more heavily in this article. Feel free to swap out the imports for &lt;code&gt;PyPDF2&lt;/code&gt; with &lt;code&gt;PyPDF4&lt;/code&gt; and see how it works for you.&lt;/p&gt;
&lt;h2 id=&quot;pdfrw-an-alternative&quot;&gt;&lt;code&gt;pdfrw&lt;/code&gt;: An Alternative&lt;/h2&gt;
&lt;p&gt;Patrick Maupin created a package called &lt;a href=&quot;https://github.com/pmaupin/pdfrw&quot;&gt;&lt;code&gt;pdfrw&lt;/code&gt;&lt;/a&gt; that can do many of the same things that &lt;code&gt;PyPDF2&lt;/code&gt; does. You can use &lt;code&gt;pdfrw&lt;/code&gt; for all of the same sorts of tasks that you will learn how to do in this article for &lt;code&gt;PyPDF2&lt;/code&gt;, with the notable exception of encryption. &lt;/p&gt;
&lt;p&gt;The biggest difference when it comes to &lt;code&gt;pdfrw&lt;/code&gt; is that it integrates with the &lt;a href=&quot;https://www.reportlab.com/&quot;&gt;ReportLab&lt;/a&gt; package so that you can take a preexisting PDF and build a new one with ReportLab using some or all of the preexisting PDF.&lt;/p&gt;
&lt;h2 id=&quot;installation&quot;&gt;Installation&lt;/h2&gt;
&lt;p&gt;Installing &lt;code&gt;PyPDF2&lt;/code&gt; can be done with &lt;code&gt;pip&lt;/code&gt; or &lt;code&gt;conda&lt;/code&gt; if you happen to be using Anaconda instead of regular Python.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s how you would install &lt;code&gt;PyPDF2&lt;/code&gt; with &lt;code&gt;pip&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight sh&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; pip install pypdf2
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The install is quite quick as &lt;code&gt;PyPDF2&lt;/code&gt; does not have any dependencies. You will likely spend as much time downloading the package as you will installing it.&lt;/p&gt;
&lt;p&gt;Now let&amp;rsquo;s move on and learn how to extract some information from a PDF.&lt;/p&gt;
&lt;h2 id=&quot;how-to-extract-document-information-from-a-pdf-in-python&quot;&gt;How to Extract Document Information From a PDF in Python&lt;/h2&gt;
&lt;p&gt;You can use &lt;code&gt;PyPDF2&lt;/code&gt; to extract metadata and some text from a PDF. This can be useful when you&amp;rsquo;re doing certain types of automation on your preexisting PDF files.&lt;/p&gt;
&lt;p&gt;Here are the current types of data that can be extracted:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Author&lt;/li&gt;
&lt;li&gt;Creator&lt;/li&gt;
&lt;li&gt;Producer&lt;/li&gt;
&lt;li&gt;Subject&lt;/li&gt;
&lt;li&gt;Title&lt;/li&gt;
&lt;li&gt;Number of pages&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You need to go find a PDF to use for this example. You can use any PDF you have handy on your machine. To make things easy, I went to &lt;a href=&quot;https://leanpub.com/reportlab&quot;&gt;Leanpub&lt;/a&gt; and grabbed a sample of one of my books for this exercise. The sample you want to download is called &lt;code&gt;reportlab-sample.pdf&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s write some code using that PDF and learn how you can get access to these attributes:&lt;/p&gt;
&lt;div class=&quot;highlight python&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;# extract_doc_info.py&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;PyPDF2&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PdfFileReader&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;extract_information&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pdf_path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pdf_path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;rb&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;pdf&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PdfFileReader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;information&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pdf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;getDocumentInfo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;number_of_pages&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pdf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;getNumPages&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;txt&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;span class=&quot;s2&quot;&gt;    Information about &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{pdf_path}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;: &lt;/span&gt;

&lt;span class=&quot;s2&quot;&gt;    Author: &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{information.author}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;s2&quot;&gt;    Creator: &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{information.creator}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;s2&quot;&gt;    Producer: &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{information.producer}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;s2&quot;&gt;    Subject: &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{information.subject}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;s2&quot;&gt;    Title: &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{information.title}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;s2&quot;&gt;    Number of pages: &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{number_of_pages}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;s2&quot;&gt;    &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;

    &lt;span class=&quot;nb&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;txt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;information&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;vm&quot;&gt;__name__&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;__main__&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;path&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;reportlab-sample.pdf&amp;#39;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;extract_information&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Here you import &lt;code&gt;PdfFileReader&lt;/code&gt; from the &lt;code&gt;PyPDF2&lt;/code&gt; package. The &lt;code&gt;PdfFileReader&lt;/code&gt; is a class with several methods for interacting with PDF files. In this example, you call &lt;code&gt;.getDocumentInfo()&lt;/code&gt;, which will return an instance of &lt;code&gt;DocumentInformation&lt;/code&gt;. This contains most of the information that you&amp;rsquo;re interested in. You also call &lt;code&gt;.getNumPages()&lt;/code&gt; on the reader object, which returns the number of pages in the document.&lt;/p&gt;
&lt;div class=&quot;alert alert-primary&quot; role=&quot;alert&quot;&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; That last code block uses Python 3&amp;rsquo;s new f-strings for string formatting. If you&amp;rsquo;d like to learn more, you can check out &lt;a href=&quot;https://realpython.com/python-f-strings/&quot;&gt;Python 3&amp;rsquo;s f-Strings: An Improved String Formatting Syntax (Guide)&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;information&lt;/code&gt; variable has several instance attributes that you can use to get the rest of the metadata you want from the document. You print out that information and also return it for potential future use.&lt;/p&gt;
&lt;p&gt;While &lt;code&gt;PyPDF2&lt;/code&gt; has &lt;code&gt;.extractText()&lt;/code&gt;, which can be used on its page objects (not shown in this example), it does not work very well. Some PDFs will return text and some will return an empty string. When you want to extract text from a PDF, you should check out the &lt;a href=&quot;https://github.com/euske/pdfminer&quot;&gt;&lt;code&gt;PDFMiner&lt;/code&gt;&lt;/a&gt; project instead. &lt;strong&gt;&lt;code&gt;PDFMiner&lt;/code&gt;&lt;/strong&gt; is much more robust and was specifically designed for extracting text from PDFs.&lt;/p&gt;
&lt;p&gt;Now you&amp;rsquo;re ready to learn about rotating PDF pages.&lt;/p&gt;
&lt;h2 id=&quot;how-to-rotate-pages&quot;&gt;How to Rotate Pages&lt;/h2&gt;
&lt;p&gt;Occasionally, you will receive PDFs that contain pages that are in &lt;a href=&quot;https://techterms.com/definition/pageorientation&quot;&gt;landscape mode&lt;/a&gt; instead of portrait mode. Or perhaps they are even upside down. This can happen when someone scans a document to PDF or email. You could print the document out and read the paper version or you can use the power of Python to rotate the offending pages.&lt;/p&gt;
&lt;p&gt;For this example, you can go and pick out a Real Python &lt;a href=&quot;https://realpython.com/jupyter-notebook-introduction/&quot;&gt;article&lt;/a&gt; and print it to PDF.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s learn how to rotate a few of the pages of that article with &lt;code&gt;PyPDF2&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight python&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;# rotate_pages.py&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;PyPDF2&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PdfFileReader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PdfFileWriter&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;rotate_pages&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pdf_path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;pdf_writer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PdfFileWriter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;pdf_reader&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PdfFileReader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# Rotate page 90 degrees to the right&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;page_1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pdf_reader&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;getPage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rotateClockwise&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;90&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;pdf_writer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;addPage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;page_1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# Rotate page 90 degrees to the left&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;page_2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pdf_reader&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;getPage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rotateCounterClockwise&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;90&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;pdf_writer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;addPage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;page_2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# Add a page in normal orientation&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;pdf_writer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;addPage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pdf_reader&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;getPage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;rotate_pages.pdf&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;wb&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;pdf_writer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;vm&quot;&gt;__name__&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;__main__&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;path&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;Jupyter_Notebook_An_Introduction.pdf&amp;#39;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;rotate_pages&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;For this example, you need to import the &lt;code&gt;PdfFileWriter&lt;/code&gt; in addition to &lt;code&gt;PdfFileReader&lt;/code&gt; because you will need to write out a new PDF. &lt;code&gt;rotate_pages()&lt;/code&gt; takes in the path to the PDF that you want to modify. Within that function, you will need to create a writer object that you can name &lt;code&gt;pdf_writer&lt;/code&gt; and a reader object called &lt;code&gt;pdf_reader&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Next, you can use &lt;code&gt;.GetPage()&lt;/code&gt; to get the desired page. Here you grab page zero, which is the first page. Then you call the page object&amp;rsquo;s &lt;code&gt;.rotateClockwise()&lt;/code&gt; method and pass in 90 degrees.  Then for page two, you call &lt;code&gt;.rotateCounterClockwise()&lt;/code&gt; and pass it 90 degrees as well.&lt;/p&gt;
&lt;div class=&quot;alert alert-primary&quot; role=&quot;alert&quot;&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The &lt;code&gt;PyPDF2&lt;/code&gt; package only allows you to rotate a page in increments of 90 degrees. You will receive an &lt;code&gt;AssertionError&lt;/code&gt; otherwise.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;After each call to the rotation methods, you call &lt;code&gt;.addPage()&lt;/code&gt;. This will add the rotated version of the page to the writer object. The last page that you add to the writer object is page 3 without any rotation done to it. &lt;/p&gt;
&lt;p&gt;Finally you write out the new PDF using &lt;code&gt;.write()&lt;/code&gt;. It takes a &lt;a href=&quot;https://docs.python.org/3/glossary.html#term-file-object&quot;&gt;file-like object&lt;/a&gt; as its parameter. This new PDF will contain three pages. The first two will be rotated in opposite directions of each other and be in landscape while the third page is a normal page. &lt;/p&gt;
&lt;p&gt;Now let&amp;rsquo;s learn how you can merge multiple PDFs into one.&lt;/p&gt;
&lt;h2 id=&quot;how-to-merge-pdfs&quot;&gt;How to Merge PDFs&lt;/h2&gt;
&lt;p&gt;There are many situations where you will want to take two or more PDFs and merge them together into a single PDF. For example, you might have a standard cover page that needs to go on to many types of reports. You can use Python to help you do that sort of thing.&lt;/p&gt;
&lt;p&gt;For this example, you can open up a PDF and print a page out as a separate PDF. Then do that again, but with a different page. That will give you a couple of inputs to use for example purposes.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s go ahead and write some code that you can use to merge PDFs together:&lt;/p&gt;
&lt;div class=&quot;highlight python&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;# pdf_merging.py&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;PyPDF2&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PdfFileReader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PdfFileWriter&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;merge_pdfs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;paths&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;output&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;pdf_writer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PdfFileWriter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;path&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;paths&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;pdf_reader&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PdfFileReader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;page&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;range&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pdf_reader&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;getNumPages&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()):&lt;/span&gt;
            &lt;span class=&quot;c1&quot;&gt;# Add each page to the writer object&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;pdf_writer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;addPage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pdf_reader&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;getPage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;page&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;# Write out the merged PDF&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;output&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;wb&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;out&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;pdf_writer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;out&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;vm&quot;&gt;__name__&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;__main__&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;paths&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;document1.pdf&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;document2.pdf&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;merge_pdfs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;paths&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;output&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;merged.pdf&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You can use &lt;code&gt;merge_pdfs()&lt;/code&gt; when you have a list of PDFs that you want to merge together. You will also need to know where to save the result, so this function takes a list of input paths and an output path.&lt;/p&gt;
&lt;p&gt;Then you loop over the inputs and create a PDF reader object for each of them. Next you will iterate over all the pages in the PDF file and use &lt;code&gt;.addPage()&lt;/code&gt; to add each of those pages to itself.&lt;/p&gt;
&lt;p&gt;Once you&amp;rsquo;re finished iterating over all of the pages of all of the PDFs in your list, you will write out the result at the end. &lt;/p&gt;
&lt;p&gt;One item I would like to point out is that you could enhance this script a bit by adding in a range of pages to be added if you didn&amp;rsquo;t want to merge all the pages of each PDF. If you&amp;rsquo;d like a challenge, you could also create a command line interface for this function using Python&amp;rsquo;s &lt;a href=&quot;https://docs.python.org/3/library/argparse.html&quot;&gt;&lt;code&gt;argparse&lt;/code&gt;&lt;/a&gt; module. &lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s find out how to do the opposite of merging!&lt;/p&gt;
&lt;h2 id=&quot;how-to-split-pdfs&quot;&gt;How to Split PDFs&lt;/h2&gt;
&lt;p&gt;There are times where you might have a PDF that you need to split up into multiple PDFs. This is especially true of PDFs that contain a lot of scanned-in content, but there are a plethora of good reasons for wanting to split a PDF.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s how you can use &lt;code&gt;PyPDF2&lt;/code&gt; to split your PDF into multiple files:&lt;/p&gt;
&lt;div class=&quot;highlight python&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;# pdf_splitting.py&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;PyPDF2&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PdfFileReader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PdfFileWriter&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name_of_split&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;pdf&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PdfFileReader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;page&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;range&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pdf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;getNumPages&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()):&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;pdf_writer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PdfFileWriter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;pdf_writer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;addPage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pdf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;getPage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;page&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;

        &lt;span class=&quot;n&quot;&gt;output&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{name_of_split}{page}&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;.pdf&amp;#39;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;output&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;wb&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;output_pdf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;pdf_writer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;output_pdf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;vm&quot;&gt;__name__&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;__main__&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;path&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;Jupyter_Notebook_An_Introduction.pdf&amp;#39;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;jupyter_page&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In this example, you once again create a PDF reader object and loop over its pages. For each page in the PDF, you will create a new PDF writer instance and add a single page to it. Then you will write that page out to a uniquely named file. When the script is finished running, you should have each page of the original PDF split into separate PDFs.&lt;/p&gt;
&lt;p&gt;Now let&amp;rsquo;s take a moment to learn how you can add a watermark to your PDF.&lt;/p&gt;
&lt;h2 id=&quot;how-to-add-watermarks&quot;&gt;How to Add Watermarks&lt;/h2&gt;
&lt;p&gt;Watermarks are identifying images or patterns on printed and digital documents. Some watermarks can only be seen in special lighting conditions. The reason watermarking is important is that it allows you to protect your intellectual property, such as your images or PDFs. Another term for watermark is overlay.&lt;/p&gt;
&lt;p&gt;You can use Python and &lt;code&gt;PyPDF2&lt;/code&gt; to watermark your documents. You need to have a PDF that only contains your watermark image or text. &lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s learn how to add a watermark now:&lt;/p&gt;
&lt;div class=&quot;highlight python&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;# pdf_watermarker.py&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;PyPDF2&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PdfFileWriter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PdfFileReader&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;create_watermark&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;input_pdf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;output&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;watermark&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;watermark_obj&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PdfFileReader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;watermark&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;watermark_page&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;watermark_obj&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;getPage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;pdf_reader&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PdfFileReader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;input_pdf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;pdf_writer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PdfFileWriter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;# Watermark all the pages&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;page&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;range&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pdf_reader&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;getNumPages&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()):&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;page&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pdf_reader&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;getPage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;page&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;page&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mergePage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;watermark_page&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;pdf_writer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;addPage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;page&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;output&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;wb&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;out&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;pdf_writer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;out&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;vm&quot;&gt;__name__&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;__main__&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;create_watermark&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;input_pdf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;Jupyter_Notebook_An_Introduction.pdf&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; 
        &lt;span class=&quot;n&quot;&gt;output&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;watermarked_notebook.pdf&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;watermark&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;watermark.pdf&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;code&gt;create_watermark()&lt;/code&gt; accepts three arguments:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;input_pdf&lt;/code&gt;:&lt;/strong&gt; the PDF file path to be watermarked&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;output&lt;/code&gt;:&lt;/strong&gt; the path you want to save the watermarked version of the PDF&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;watermark&lt;/code&gt;:&lt;/strong&gt; a PDF that contains your watermark image or text&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;In the code, you open up the watermark PDF and grab just the first page from the document as that is where your watermark should reside. Then you create a PDF reader object using the &lt;code&gt;input_pdf&lt;/code&gt; and a generic &lt;code&gt;pdf_writer&lt;/code&gt; object for writing out the watermarked PDF.&lt;/p&gt;
&lt;p&gt;The next step is to iterate over the pages in the &lt;code&gt;input_pdf&lt;/code&gt;. This is where the magic happens. You will need to call  &lt;code&gt;.mergePage()&lt;/code&gt; and pass it the &lt;code&gt;watermark_page&lt;/code&gt;. When you do that, it will overlay the &lt;code&gt;watermark_page&lt;/code&gt; on top of the current page. Then you add that newly merged page to your &lt;code&gt;pdf_writer&lt;/code&gt; object.&lt;/p&gt;
&lt;p&gt;Finally, you write the newly watermarked PDF out to disk, and you&amp;rsquo;re done!&lt;/p&gt;
&lt;p&gt;The last topic you will learn about is how &lt;code&gt;PyPDF2&lt;/code&gt; handles encryption.&lt;/p&gt;
&lt;h2 id=&quot;how-to-encrypt-a-pdf&quot;&gt;How to Encrypt a PDF&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;PyPDF2&lt;/code&gt; currently only supports adding a user password and an owner password to a preexisting PDF. In PDF land, an owner password will basically give you administrator privileges over the PDF and allow you to set permissions on the document. On the other hand, the user password just allows you to open the document.&lt;/p&gt;
&lt;p&gt;As far as I can tell, &lt;code&gt;PyPDF2&lt;/code&gt; doesn&amp;rsquo;t actually allow you to set any permissions on the document even though it does allow you to set the owner password.&lt;/p&gt;
&lt;p&gt;Regardless, this is how you can add a password, which will also inherently encrypt the PDF:&lt;/p&gt;
&lt;div class=&quot;highlight python&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;# pdf_encrypt.py&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;PyPDF2&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PdfFileWriter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PdfFileReader&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;add_encryption&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;input_pdf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;output_pdf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;password&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;pdf_writer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PdfFileWriter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;pdf_reader&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PdfFileReader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;input_pdf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;page&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;range&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pdf_reader&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;getNumPages&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()):&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;pdf_writer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;addPage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pdf_reader&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;getPage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;page&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;pdf_writer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;encrypt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;user_pwd&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;password&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;owner_pwd&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; 
                       &lt;span class=&quot;n&quot;&gt;use_128bit&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;output_pdf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;wb&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;pdf_writer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;vm&quot;&gt;__name__&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;__main__&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;add_encryption&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;input_pdf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;reportlab-sample.pdf&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                   &lt;span class=&quot;n&quot;&gt;output_pdf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;reportlab-encrypted.pdf&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                   &lt;span class=&quot;n&quot;&gt;password&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;twofish&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;code&gt;add_encryption()&lt;/code&gt; takes in the input and output PDF paths as well as the password that you want to add to the PDF. It then opens a PDF writer and a reader object, as before. Since you will want to encrypt the entire input PDF, you will need to loop over all of its pages and add them to the writer.&lt;/p&gt;
&lt;p&gt;The final step is to call &lt;code&gt;.encrypt()&lt;/code&gt;, which takes the user password, the owner password, and whether or not 128-bit encryption should be added. The default is for 128-bit encryption to be turned on. If you set it to &lt;code&gt;False&lt;/code&gt;, then 40-bit encryption will be applied instead.&lt;/p&gt;
&lt;div class=&quot;alert alert-primary&quot; role=&quot;alert&quot;&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; PDF encryption uses either RC4 or AES (Advanced Encryption Standard) to encrypt the PDF according to &lt;a href=&quot;https://www.pdflib.com/pdf-knowledge-base/pdf-password-security/encryption/&quot;&gt;pdflib.com&lt;/a&gt;. &lt;/p&gt;
&lt;p&gt;Just because you have encrypted your PDF does not mean it is necessarily secure. There are tools to remove passwords from PDFs. If you&amp;rsquo;d like to learn more, Carnegie Mellon University has an interesting &lt;a href=&quot;https://www.cs.cmu.edu/~dst/Adobe/Gallery/PDFsecurity.pdf&quot;&gt;paper on the topic&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;PyPDF2&lt;/code&gt; package is quite useful and is usually pretty fast. You can use &lt;code&gt;PyPDF2&lt;/code&gt; to automate large jobs and leverage its capabilities to help you do your job better!&lt;/p&gt;
&lt;p&gt;In this tutorial, you learned how to do the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Extract metadata from a PDF&lt;/li&gt;
&lt;li&gt;Rotate pages&lt;/li&gt;
&lt;li&gt;Merge and split PDFs&lt;/li&gt;
&lt;li&gt;Add watermarks&lt;/li&gt;
&lt;li&gt;Add encryption&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Also keep an eye on the newer &lt;code&gt;PyPDF4&lt;/code&gt; package as it will likely replace &lt;code&gt;PyPDF2&lt;/code&gt; soon. You might also want to check out &lt;a href=&quot;https://github.com/pmaupin/pdfrw&quot;&gt;&lt;code&gt;pdfrw&lt;/code&gt;&lt;/a&gt;, which can do many of the same things that &lt;code&gt;PyPDF2&lt;/code&gt; can do.&lt;/p&gt;
&lt;h2 id=&quot;further-reading&quot;&gt;Further Reading&lt;/h2&gt;
&lt;p&gt;If you&amp;rsquo;d like to learn more about working with PDFs in Python, you should check out some of the following resources for more information:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://pythonhosted.org/PyPDF2/&quot;&gt;The &lt;code&gt;PyPDF2&lt;/code&gt; website&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/claird/PyPDF4&quot;&gt;The Github page for &lt;code&gt;PyPDF4&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/pmaupin/pdfrw&quot;&gt;The Github page for &lt;code&gt;pdfrw&lt;/code&gt;&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.reportlab.com/&quot;&gt;The ReportLab website&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/euske/pdfminer&quot;&gt;The Github page for &lt;code&gt;PDFMiner&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/socialcopsdev/camelot&quot;&gt;Camelot:  PDF Table Extraction for Humans&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
        &lt;hr /&gt;
        &lt;p&gt;&lt;em&gt;[ Improve Your Python With 🐍 Python Tricks 💌 – Get a short &amp;amp; sweet Python Trick delivered to your inbox every couple of days. &lt;a href=&quot;https://realpython.com/python-tricks/?utm_source=realpython&amp;amp;utm_medium=rss&amp;amp;utm_campaign=footer&quot;&gt;&amp;gt;&amp;gt; Click here to learn more and see examples&lt;/a&gt; ]&lt;/em&gt;&lt;/p&gt;
      </content>
    </entry>
  
    <entry>
      <title>Hands-on Python 3 Concurrency With the asyncio Module</title>
      <id>https://realpython.com/courses/python-3-concurrency-asyncio-module/</id>
      <link href="https://realpython.com/courses/python-3-concurrency-asyncio-module/"/>
      <updated>2019-04-16T14:00:00+00:00</updated>
      <summary>Learn how to speed up your Python 3 programs using concurrency and the asyncio module in the standard library. See step-by-step how to leverage concurrency and parallelism in your own programs, all the way to building a complete HTTP downloader example app using asyncio and aiohttp.</summary>
      <content type="html">
        &lt;p&gt;Learn how to speed up your Python 3 programs using concurrency and the new &lt;code&gt;asyncio&lt;/code&gt; module in the standard library. &lt;/p&gt;
&lt;p&gt;First, you&amp;rsquo;ll explore the key terms of parallel programming. Next, you&amp;rsquo;ll see step-by-step how to leverage concurrency and parallelism in your own programs, all the way to building a complete HTTP downloader example app using &lt;code&gt;asyncio&lt;/code&gt; and &lt;code&gt;aiohttp&lt;/code&gt;.&lt;/p&gt;
        &lt;hr /&gt;
        &lt;p&gt;&lt;em&gt;[ Improve Your Python With 🐍 Python Tricks 💌 – Get a short &amp;amp; sweet Python Trick delivered to your inbox every couple of days. &lt;a href=&quot;https://realpython.com/python-tricks/?utm_source=realpython&amp;amp;utm_medium=rss&amp;amp;utm_campaign=footer&quot;&gt;&amp;gt;&amp;gt; Click here to learn more and see examples&lt;/a&gt; ]&lt;/em&gt;&lt;/p&gt;
      </content>
    </entry>
  
    <entry>
      <title>Linear Regression in Python</title>
      <id>https://realpython.com/linear-regression-in-python/</id>
      <link href="https://realpython.com/linear-regression-in-python/"/>
      <updated>2019-04-15T14:00:00+00:00</updated>
      <summary>In this step-by-step tutorial, you&#39;ll get started with linear regression in Python. Linear regression is one of the fundamental statistical and machine learning techniques, and Python is a popular choice for machine learning.</summary>
      <content type="html">
        &lt;p&gt;We&amp;rsquo;re living in the era of large amounts of &lt;a href=&quot;https://realpython.com/tutorials/data-science/&quot;&gt;data&lt;/a&gt;, powerful computers, and artificial intelligence. This is just the beginning. &lt;a href=&quot;https://realpython.com/data-science-podcasts/&quot;&gt;Data science&lt;/a&gt; and machine learning are driving image recognition, autonomous vehicles development, decisions in the financial and energy sectors, advances in medicine, the rise of social networks, and more. Linear regression is an important part of this.&lt;/p&gt;
&lt;p&gt;Linear regression is one of the fundamental statistical and machine learning techniques. Whether you want to do statistics, &lt;a href=&quot;https://realpython.com/tutorials/machine-learning/&quot;&gt;machine learning&lt;/a&gt;, or scientific computing, there are good chances that you&amp;rsquo;ll need it. It&amp;rsquo;s advisable to learn it first and then proceed towards more complex methods.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;By the end of this article, you&amp;rsquo;ll have learned:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;What linear regression is&lt;/li&gt;
&lt;li&gt;What linear regression is used for&lt;/li&gt;
&lt;li&gt;How linear regression works&lt;/li&gt;
&lt;li&gt;How to implement linear regression in Python, step by step&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;alert alert-warning&quot; role=&quot;alert&quot;&gt;&lt;p&gt;&lt;strong&gt;Free Bonus:&lt;/strong&gt; &lt;a href=&quot;#&quot; class=&quot;alert-link&quot; data-toggle=&quot;modal&quot; data-target=&quot;#modal-numpy-learning-guide&quot; data-focus=&quot;false&quot;&gt;Click here to get access to a free NumPy Resources Guide&lt;/a&gt; that points you to the best tutorials, videos, and books for improving your NumPy skills.&lt;/p&gt;&lt;/div&gt;

&lt;h2 id=&quot;regression&quot;&gt;Regression&lt;/h2&gt;
&lt;p&gt;Regression analysis is one of the most important fields in statistics and machine learning. There are many regression methods available. Linear regression is one of them.&lt;/p&gt;
&lt;h3 id=&quot;what-is-regression&quot;&gt;What Is Regression?&lt;/h3&gt;
&lt;p&gt;Regression searches for relationships among variables.&lt;/p&gt;
&lt;p&gt;For example, you can observe several employees of some company and try to understand how their salaries depend on the &lt;strong&gt;features&lt;/strong&gt;, such as experience, level of education, role, city they work in, and so on.&lt;/p&gt;
&lt;p&gt;This is a regression problem where data related to each employee represent one &lt;strong&gt;observation&lt;/strong&gt;. The presumption is that the experience, education, role, and city are the independent features, while the salary depends on them.&lt;/p&gt;
&lt;p&gt;Similarly, you can try to establish a mathematical dependence of the prices of houses on their areas, numbers of bedrooms, distances to the city center, and so on.&lt;/p&gt;
&lt;p&gt;Generally, in regression analysis, you usually consider some phenomenon of interest and have a number of observations. Each observation has two or more features. Following the assumption that (at least) one of the features depends on the others, you try to establish a relation among them.&lt;/p&gt;
&lt;p&gt;In other words, &lt;strong&gt;you need to find a function that maps some features or variables to others sufficiently well&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;The dependent features are called the &lt;strong&gt;dependent variables&lt;/strong&gt;, &lt;strong&gt;outputs&lt;/strong&gt;, or &lt;strong&gt;responses&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;The independent features are called the &lt;strong&gt;independent variables&lt;/strong&gt;, &lt;strong&gt;inputs&lt;/strong&gt;, or &lt;strong&gt;predictors&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Regression problems usually have one continuous and unbounded dependent variable. The inputs, however, can be continuous, discrete, or even categorical data such as gender, nationality, brand, and so on.&lt;/p&gt;
&lt;p&gt;It is a common practice to denote the outputs with 𝑦 and inputs with 𝑥. If there are two or more independent variables, they can be represented as the vector 𝐱 = (𝑥₁, …, 𝑥ᵣ), where 𝑟 is the number of inputs.&lt;/p&gt;
&lt;h3 id=&quot;when-do-you-need-regression&quot;&gt;When Do You Need Regression?&lt;/h3&gt;
&lt;p&gt;Typically, you need regression to answer whether and how some phenomenon influences the other or &lt;strong&gt;how several variables are related&lt;/strong&gt;. For example, you can use it to determine &lt;em&gt;if&lt;/em&gt; and &lt;em&gt;to what extent&lt;/em&gt; the experience or gender impact salaries.&lt;/p&gt;
&lt;p&gt;Regression is also useful when you want &lt;strong&gt;to forecast a response&lt;/strong&gt; using a new set of predictors. For example, you could try to predict electricity consumption of a household for the next hour given the outdoor temperature, time of day, and number of residents in that household.&lt;/p&gt;
&lt;p&gt;Regression is used in many different fields: economy, computer science, social sciences, and so on. Its importance rises every day with the availability of large amounts of data and increased awareness of the practical value of data.&lt;/p&gt;
&lt;h2 id=&quot;linear-regression&quot;&gt;Linear Regression&lt;/h2&gt;
&lt;p&gt;Linear regression is probably one of the most important and widely used regression techniques. It&amp;rsquo;s among the simplest regression methods. One of its main advantages is the ease of interpreting results.&lt;/p&gt;
&lt;h3 id=&quot;problem-formulation&quot;&gt;Problem Formulation&lt;/h3&gt;
&lt;p&gt;When implementing linear regression of some dependent variable 𝑦 on the set of independent variables 𝐱 = (𝑥₁, …, 𝑥ᵣ), where 𝑟 is the number of predictors, you assume a linear relationship between 𝑦 and 𝐱: 𝑦 = 𝛽₀ + 𝛽₁𝑥₁ + ⋯ + 𝛽ᵣ𝑥ᵣ + 𝜀. This equation is the &lt;strong&gt;regression equation&lt;/strong&gt;. 𝛽₀, 𝛽₁, …, 𝛽ᵣ are the &lt;strong&gt;regression coefficients&lt;/strong&gt;, and 𝜀 is the &lt;strong&gt;random error&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Linear regression calculates the &lt;strong&gt;estimators&lt;/strong&gt; of the regression coefficients or simply the &lt;strong&gt;predicted weights&lt;/strong&gt;, denoted with 𝑏₀, 𝑏₁, …, 𝑏ᵣ. They define the &lt;strong&gt;estimated regression function&lt;/strong&gt; 𝑓(𝐱) = 𝑏₀ + 𝑏₁𝑥₁ + ⋯ + 𝑏ᵣ𝑥ᵣ. This function should capture the dependencies between the inputs and output sufficiently well.&lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;estimated&lt;/strong&gt; or &lt;strong&gt;predicted response&lt;/strong&gt;, 𝑓(𝐱ᵢ), for each observation 𝑖 = 1, …, 𝑛, should be as close as possible to the corresponding &lt;strong&gt;actual response&lt;/strong&gt; 𝑦ᵢ. The differences 𝑦ᵢ - 𝑓(𝐱ᵢ) for all observations 𝑖 = 1, …, 𝑛, are called the &lt;strong&gt;residuals&lt;/strong&gt;. Regression is about determining the &lt;strong&gt;best predicted weights&lt;/strong&gt;, that is the weights corresponding to the smallest residuals.&lt;/p&gt;
&lt;p&gt;To get the best weights, you usually &lt;strong&gt;minimize the sum of squared residuals&lt;/strong&gt; (SSR) for all observations 𝑖 = 1, …, 𝑛: SSR = Σᵢ(𝑦ᵢ - 𝑓(𝐱ᵢ))². This approach is called the &lt;strong&gt;method of ordinary least squares&lt;/strong&gt;.&lt;/p&gt;
&lt;h3 id=&quot;regression-performance&quot;&gt;Regression Performance&lt;/h3&gt;
&lt;p&gt;The variation of actual responses 𝑦ᵢ, 𝑖 = 1, …, 𝑛, occurs partly due to the dependence on the predictors 𝐱ᵢ. However, there is also an additional inherent variance of the output.&lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;coefficient of determination&lt;/strong&gt;, denoted as 𝑅², tells you which amount of variation in 𝑦 can be explained by the dependence on 𝐱 using the particular regression model. Larger 𝑅² indicates a better fit and means that the model can better explain the variation of the output with different inputs.&lt;/p&gt;
&lt;p&gt;The value 𝑅² = 1 corresponds to SSR = 0, that is to the &lt;strong&gt;perfect fit&lt;/strong&gt; since the values of predicted and actual responses fit completely to each other.&lt;/p&gt;
&lt;h3 id=&quot;simple-linear-regression&quot;&gt;Simple Linear Regression&lt;/h3&gt;
&lt;p&gt;Simple or single-variate linear regression is the simplest case of linear regression with a single independent variable, 𝐱 = 𝑥.&lt;/p&gt;
&lt;p&gt;The following figure illustrates simple linear regression:&lt;/p&gt;
&lt;figure class=&quot;figure mx-auto d-block&quot;&gt;&lt;a href=&quot;https://files.realpython.com/media/fig-lin-reg.a506035b654a.png&quot; target=&quot;_blank&quot;&gt;&lt;img class=&quot;img-fluid mx-auto d-block &quot; src=&quot;https://files.realpython.com/media/fig-lin-reg.a506035b654a.png&quot; width=&quot;950&quot; height=&quot;481&quot; srcset=&quot;https://robocrop.realpython.net/?url=https%3A//files.realpython.com/media/fig-lin-reg.a506035b654a.png&amp;amp;w=237&amp;amp;sig=ccb74ab08d560aceb779a10de4507db4f97000be 237w, https://robocrop.realpython.net/?url=https%3A//files.realpython.com/media/fig-lin-reg.a506035b654a.png&amp;amp;w=475&amp;amp;sig=dfa9f07896d01e38bb307a25b45ca82dee604c8b 475w, https://files.realpython.com/media/fig-lin-reg.a506035b654a.png 950w&quot; sizes=&quot;75vw&quot; alt=&quot;Example of simple linear regression&quot;/&gt;&lt;/a&gt;&lt;figcaption class=&quot;figure-caption text-center&quot;&gt;Example of simple linear regression&lt;/figcaption&gt;&lt;/figure&gt;

&lt;p&gt;When implementing simple linear regression, you typically start with a given set of input-output (𝑥-𝑦) pairs (green circles). These pairs are your observations. For example, the leftmost observation (green circle) has the input 𝑥 = 5 and the actual output (response) 𝑦 = 5. The next one has 𝑥 = 15 and 𝑦 = 20, and so on.&lt;/p&gt;
&lt;p&gt;The estimated regression function (black line) has the equation 𝑓(𝑥) = 𝑏₀ + 𝑏₁𝑥. Your goal is to calculate the optimal values of the predicted weights 𝑏₀ and 𝑏₁ that minimize SSR and determine the estimated regression function. The value of 𝑏₀, also called the &lt;strong&gt;intercept&lt;/strong&gt;, shows the point where the estimated regression line crosses the 𝑦 axis. It is the value of the estimated response 𝑓(𝑥) for 𝑥 = 0. The value of 𝑏₁ determines the &lt;strong&gt;slope&lt;/strong&gt; of the estimated regression line.&lt;/p&gt;
&lt;p&gt;The predicted responses (red squares) are the points on the regression line that correspond to the input values. For example, for the input 𝑥 = 5, the predicted response is 𝑓(5) = 8.33 (represented with the leftmost red square).&lt;/p&gt;
&lt;p&gt;The residuals (vertical dashed gray lines) can be calculated as 𝑦ᵢ - 𝑓(𝐱ᵢ) = 𝑦ᵢ - 𝑏₀ - 𝑏₁𝑥ᵢ for 𝑖 = 1, …, 𝑛. They are the distances between the green circles and red squares. When you implement linear regression, you are actually trying to minimize these distances and make the red squares as close to the predefined green circles as possible.&lt;/p&gt;
&lt;h3 id=&quot;multiple-linear-regression&quot;&gt;Multiple Linear Regression&lt;/h3&gt;
&lt;p&gt;Multiple or multivariate linear regression is a case of linear regression with two or more independent variables.&lt;/p&gt;
&lt;p&gt;If there are just two independent variables, the estimated regression function is 𝑓(𝑥₁, 𝑥₂) = 𝑏₀ + 𝑏₁𝑥₁ + 𝑏₂𝑥₂. It represents a regression plane in a three-dimensional space. The goal of regression is to determine the values of the weights 𝑏₀, 𝑏₁, and 𝑏₂ such that this plane is as close as possible to the actual responses and yield the minimal SSR.&lt;/p&gt;
&lt;p&gt;The case of more than two independent variables is similar, but more general. The estimated regression function is 𝑓(𝑥₁, …, 𝑥ᵣ) = 𝑏₀ + 𝑏₁𝑥₁ + ⋯ +𝑏ᵣ𝑥ᵣ, and there are 𝑟 + 1 weights to be determined when the number of inputs is 𝑟.&lt;/p&gt;
&lt;h3 id=&quot;polynomial-regression&quot;&gt;Polynomial Regression&lt;/h3&gt;
&lt;p&gt;You can regard polynomial regression as a generalized case of linear regression. You assume the polynomial dependence between the output and inputs and, consequently, the polynomial estimated regression function.&lt;/p&gt;
&lt;p&gt;In other words, in addition to linear terms like 𝑏₁𝑥₁, your regression function 𝑓 can include non-linear terms such as 𝑏₂𝑥₁², 𝑏₃𝑥₁³, or even 𝑏₄𝑥₁𝑥₂, 𝑏₅𝑥₁²𝑥₂, and so on.&lt;/p&gt;
&lt;p&gt;The simplest example of polynomial regression has a single independent variable, and the estimated regression function is a polynomial of degree 2: 𝑓(𝑥) = 𝑏₀ + 𝑏₁𝑥 + 𝑏₂𝑥².&lt;/p&gt;
&lt;p&gt;Now, remember that you want to calculate 𝑏₀, 𝑏₁, and 𝑏₂, which minimize SSR. These are your unknowns! &lt;/p&gt;
&lt;p&gt;Keeping this in mind, compare the previous regression function with the function 𝑓(𝑥₁, 𝑥₂) = 𝑏₀ + 𝑏₁𝑥₁ + 𝑏₂𝑥₂ used for linear regression. They look very similar and are both linear functions of the unknowns 𝑏₀, 𝑏₁, and 𝑏₂. This is why you can &lt;strong&gt;solve the polynomial regression problem as a linear problem&lt;/strong&gt; with the term 𝑥² regarded as an input variable.&lt;/p&gt;
&lt;p&gt;In the case of two variables and the polynomial of degree 2, the regression function has this form: 𝑓(𝑥₁, 𝑥₂) = 𝑏₀ + 𝑏₁𝑥₁ + 𝑏₂𝑥₂ + 𝑏₃𝑥₁² + 𝑏₄𝑥₁𝑥₂ + 𝑏₅𝑥₂². The procedure for solving the problem is identical to the previous case. You apply linear regression for five inputs: 𝑥₁, 𝑥₂, 𝑥₁², 𝑥₁𝑥₂, and 𝑥₂². What you get as the result of regression are the values of six weights which minimize SSR: 𝑏₀, 𝑏₁, 𝑏₂, 𝑏₃, 𝑏₄, and 𝑏₅.&lt;/p&gt;
&lt;p&gt;Of course, there are more general problems, but this should be enough to illustrate the point.&lt;/p&gt;
&lt;h3 id=&quot;underfitting-and-overfitting&quot;&gt;Underfitting and Overfitting&lt;/h3&gt;
&lt;p&gt;One very important question that might arise when you&amp;rsquo;re implementing polynomial regression is related to &lt;strong&gt;the choice of the optimal degree of the polynomial regression function&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;There is no straightforward rule for doing this. It depends on the case. You should, however, be aware of two problems that might follow the choice of the degree: &lt;strong&gt;underfitting&lt;/strong&gt; and &lt;strong&gt;overfitting&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Underfitting&lt;/strong&gt; occurs when a model can&amp;rsquo;t accurately capture the dependencies among data, usually as a consequence of its own simplicity. It often yields a low 𝑅² with known data and bad generalization capabilities when applied with new data.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Overfitting&lt;/strong&gt; happens when a model learns both dependencies among data and random fluctuations. In other words, a model learns the existing data too well. Complex models, which have many features or terms, are often prone to overfitting. When applied to known data, such models usually yield high 𝑅². However, they often don&amp;rsquo;t generalize well and have significantly lower 𝑅² when used with new data.&lt;/p&gt;
&lt;p&gt;The next figure illustrates the underfitted, well-fitted, and overfitted models:&lt;/p&gt;
&lt;figure class=&quot;figure mx-auto d-block&quot;&gt;&lt;a href=&quot;https://files.realpython.com/media/poly-reg.5790f47603d8.png&quot; target=&quot;_blank&quot;&gt;&lt;img class=&quot;img-fluid mx-auto d-block &quot; src=&quot;https://files.realpython.com/media/poly-reg.5790f47603d8.png&quot; width=&quot;946&quot; height=&quot;933&quot; srcset=&quot;https://robocrop.realpython.net/?url=https%3A//files.realpython.com/media/poly-reg.5790f47603d8.png&amp;amp;w=236&amp;amp;sig=785372237ae2c73a587d77619f23edbc4834a8a0 236w, https://robocrop.realpython.net/?url=https%3A//files.realpython.com/media/poly-reg.5790f47603d8.png&amp;amp;w=473&amp;amp;sig=be83466567e91dc253f2040eb9ea907ca1617fdf 473w, https://files.realpython.com/media/poly-reg.5790f47603d8.png 946w&quot; sizes=&quot;75vw&quot; alt=&quot;Example of underfitted, well-fitted and overfitted models&quot;/&gt;&lt;/a&gt;&lt;figcaption class=&quot;figure-caption text-center&quot;&gt;Example of underfitted, well-fitted and overfitted models&lt;/figcaption&gt;&lt;/figure&gt;

&lt;p&gt;The top left plot shows a linear regression line that has a low 𝑅². It might also be important that a straight line can&amp;rsquo;t take into account the fact that the actual response increases as 𝑥 moves away from 25 towards zero. This is likely an example of underfitting.&lt;/p&gt;
&lt;p&gt;The top right plot illustrates polynomial regression with the degree equal to 2. In this instance, this might be the optimal degree for modeling this data. The model has a value of 𝑅² that is satisfactory in many cases and shows trends nicely.&lt;/p&gt;
&lt;p&gt;The bottom left plot presents polynomial regression with the degree equal to 3. The value of 𝑅² is higher than in the preceding cases. This model behaves better with known data than the previous ones. However, it shows some signs of overfitting, especially for the input values close to 60 where the line starts decreasing, although actual data don&amp;rsquo;t show that.&lt;/p&gt;
&lt;p&gt;Finally, on the bottom right plot, you can see the perfect fit: six points and the polynomial line of the degree 5 (or higher) yield 𝑅² = 1. 
Each actual response equals its corresponding prediction. &lt;/p&gt;
&lt;p&gt;In some situations, this might be exactly what you&amp;rsquo;re looking for. In many cases, however, this is an overfitted model. It is likely to have poor behavior with unseen data, especially with the inputs larger than 50.&lt;/p&gt;
&lt;p&gt;For example, it assumes, without any evidence, that there is a significant drop in responses for 𝑥 &amp;gt; 50 and that 𝑦 reaches zero for 𝑥 near 60. Such behavior is the consequence of excessive effort to learn and fit the existing data.&lt;/p&gt;
&lt;p&gt;There are a lot of resources where you can find more information about regression in general and linear regression in particular. The &lt;a href=&quot;https://en.wikipedia.org/wiki/Regression_analysis&quot;&gt;regression analysis page on Wikipedia&lt;/a&gt;, &lt;a href=&quot;https://en.wikipedia.org/wiki/Linear_regression&quot;&gt;Wikipedia&amp;rsquo;s linear regression article&lt;/a&gt;, as well as &lt;a href=&quot;https://www.khanacademy.org/math/statistics-probability/describing-relationships-quantitative-data/introduction-to-trend-lines/a/linear-regression-review&quot;&gt;Khan Academy&amp;rsquo;s linear regression article&lt;/a&gt; are good starting points.&lt;/p&gt;
&lt;h2 id=&quot;implementing-linear-regression-in-python&quot;&gt;Implementing Linear Regression in Python&lt;/h2&gt;
&lt;p&gt;It&amp;rsquo;s time to start implementing linear regression in Python. Basically, all you should do is apply the proper packages and their functions and classes.&lt;/p&gt;
&lt;h3 id=&quot;python-packages-for-linear-regression&quot;&gt;Python Packages for Linear Regression&lt;/h3&gt;
&lt;p&gt;The package &lt;strong&gt;NumPy&lt;/strong&gt; is a fundamental Python scientific package that allows many high-performance operations on single- and multi-dimensional arrays. It also offers many mathematical routines. Of course, it&amp;rsquo;s open source.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re not familiar with NumPy, you can use the official &lt;a href=&quot;https://docs.scipy.org/doc/numpy/user/index.html&quot;&gt;NumPy User Guide&lt;/a&gt; and read &lt;a href=&quot;https://realpython.com/numpy-array-programming/&quot;&gt;Look Ma, No For-Loops: Array Programming With NumPy&lt;/a&gt;. In addition, &lt;a href=&quot;https://realpython.com/numpy-tensorflow-performance/&quot;&gt;Pure Python vs NumPy vs TensorFlow Performance Comparison&lt;/a&gt; can give you a pretty good idea on the performance gains you can achieve when applying NumPy.&lt;/p&gt;
&lt;p&gt;The package &lt;strong&gt;scikit-learn&lt;/strong&gt; is a widely used Python library for machine learning, built on top of NumPy and some other packages. It provides the means for preprocessing data, reducing dimensionality, implementing regression, classification, clustering, and more. Like NumPy, scikit-learn is also open source.&lt;/p&gt;
&lt;p&gt;You can check the page &lt;a href=&quot;https://scikit-learn.org/stable/modules/linear_model.html&quot;&gt;Generalized Linear Models&lt;/a&gt; on the &lt;a href=&quot;https://scikit-learn.org/stable/&quot;&gt;scikit-learn web site&lt;/a&gt; to learn more about linear models and get deeper insight into how this package works.&lt;/p&gt;
&lt;p&gt;If you want to implement linear regression and need the functionality beyond the scope of scikit-learn, you should consider &lt;strong&gt;&lt;code&gt;statsmodels&lt;/code&gt;&lt;/strong&gt;. It&amp;rsquo;s a powerful Python package for the estimation of statistical models, performing tests, and more. It&amp;rsquo;s open source as well.&lt;/p&gt;
&lt;p&gt;You can find more information on &lt;code&gt;statsmodels&lt;/code&gt; on &lt;a href=&quot;https://www.statsmodels.org/stable/index.html&quot;&gt;its official web site&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;simple-linear-regression-with-scikit-learn&quot;&gt;Simple Linear Regression With scikit-learn&lt;/h3&gt;
&lt;p&gt;Let&amp;rsquo;s start with the simplest case, which is simple linear regression.&lt;/p&gt;
&lt;p&gt;There are five basic steps when you&amp;rsquo;re implementing linear regression:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Import the packages and classes you need.&lt;/li&gt;
&lt;li&gt;Provide data to work with and eventually do appropriate transformations.&lt;/li&gt;
&lt;li&gt;Create a regression model and fit it with existing data.&lt;/li&gt;
&lt;li&gt;Check the results of model fitting to know whether the model is satisfactory.&lt;/li&gt;
&lt;li&gt;Apply the model for predictions.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;These steps are more or less general for most of the regression approaches and implementations.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 1: Import packages and classes&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The first step is to import the package &lt;code&gt;numpy&lt;/code&gt; and the class &lt;code&gt;LinearRegression&lt;/code&gt; from &lt;code&gt;sklearn.linear_model&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight python&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;numpy&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;np&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;sklearn.linear_model&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LinearRegression&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now, you have all the functionalities you need to implement linear regression.&lt;/p&gt;
&lt;p&gt;The fundamental data type of NumPy is the array type called &lt;code&gt;numpy.ndarray&lt;/code&gt;. The rest of this article uses the term &lt;strong&gt;array&lt;/strong&gt; to refer to instances of the type &lt;code&gt;numpy.ndarray&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The class &lt;code&gt;sklearn.linear_model.LinearRegression&lt;/code&gt; will be used to perform linear and polynomial regression and make predictions accordingly.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 2: Provide data&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The second step is defining data to work with. The inputs (regressors, 𝑥) and output (predictor, 𝑦) should be arrays (the instances of the class &lt;code&gt;numpy.ndarray&lt;/code&gt;) or similar objects. This is the simplest way of providing data for regression:&lt;/p&gt;
&lt;div class=&quot;highlight python&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;15&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;25&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;35&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;45&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;55&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;reshape&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;14&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;22&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;38&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now, you have two arrays: the input &lt;code&gt;x&lt;/code&gt; and output &lt;code&gt;y&lt;/code&gt;. You should call &lt;code&gt;.reshape()&lt;/code&gt; on &lt;code&gt;x&lt;/code&gt; because this array is required to be &lt;strong&gt;two-dimensional&lt;/strong&gt;, or to be more precise, to have &lt;strong&gt;one column and as many rows as necessary&lt;/strong&gt;. That&amp;rsquo;s exactly what the argument &lt;code&gt;(-1, 1)&lt;/code&gt; of &lt;code&gt;.reshape()&lt;/code&gt; specifies. &lt;/p&gt;
&lt;p&gt;This is how &lt;code&gt;x&lt;/code&gt; and &lt;code&gt;y&lt;/code&gt; look now:&lt;/p&gt;
&lt;div class=&quot;highlight python pycon&quot;&gt;&lt;span class=&quot;repl-toggle&quot; title=&quot;Toggle REPL prompts and output&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;[[ 5]&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt; [15]&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt; [25]&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt; [35]&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt; [45]&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt; [55]]&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;[ 5 20 14 32 22 38]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;As you can see, &lt;code&gt;x&lt;/code&gt; has two dimensions, and &lt;code&gt;x.shape&lt;/code&gt; is &lt;code&gt;(6, 1)&lt;/code&gt;, while &lt;code&gt;y&lt;/code&gt; has a single dimension, and &lt;code&gt;y.shape&lt;/code&gt; is &lt;code&gt;(6,)&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 3: Create a model and fit it&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The next step is to create a linear regression model and fit it using the existing data.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s create an instance of the class &lt;code&gt;LinearRegression&lt;/code&gt;, which will represent the regression model:&lt;/p&gt;
&lt;div class=&quot;highlight python&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;model&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LinearRegression&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This statement creates the variable &lt;code&gt;model&lt;/code&gt; as the instance of &lt;code&gt;LinearRegression&lt;/code&gt;. You can provide several optional parameters to &lt;code&gt;LinearRegression&lt;/code&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;fit_intercept&lt;/code&gt;&lt;/strong&gt; is a Boolean (&lt;code&gt;True&lt;/code&gt; by default) that decides whether to calculate the intercept 𝑏₀ (&lt;code&gt;True&lt;/code&gt;) or consider it equal to zero (&lt;code&gt;False&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;normalize&lt;/code&gt;&lt;/strong&gt; is a Boolean (&lt;code&gt;False&lt;/code&gt; by default) that decides whether to normalize the input variables (&lt;code&gt;True&lt;/code&gt;) or not (&lt;code&gt;False&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;copy_X&lt;/code&gt;&lt;/strong&gt; is a Boolean (&lt;code&gt;True&lt;/code&gt; by default) that decides whether to copy (&lt;code&gt;True&lt;/code&gt;) or overwrite the input variables (&lt;code&gt;False&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;n_jobs&lt;/code&gt;&lt;/strong&gt; is an integer or &lt;code&gt;None&lt;/code&gt; (default) and represents the number of jobs used in parallel computation. &lt;code&gt;None&lt;/code&gt; usually means one job and &lt;code&gt;-1&lt;/code&gt; to use all processors.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This example uses the default values of all parameters.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s time to start using the model. First, you need to call &lt;code&gt;.fit()&lt;/code&gt; on &lt;code&gt;model&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight python&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;With &lt;code&gt;.fit()&lt;/code&gt;, you calculate the optimal values of the weights 𝑏₀ and 𝑏₁, using the existing input and output (&lt;code&gt;x&lt;/code&gt; and &lt;code&gt;y&lt;/code&gt;) as the arguments. In other words, &lt;code&gt;.fit()&lt;/code&gt; &lt;strong&gt;fits the model&lt;/strong&gt;. It returns &lt;code&gt;self&lt;/code&gt;, which is the variable &lt;code&gt;model&lt;/code&gt; itself. That&amp;rsquo;s why you can replace the last two statements with this one:&lt;/p&gt;
&lt;div class=&quot;highlight python&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;model&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LinearRegression&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This statement does the same thing as the previous two. It&amp;rsquo;s just shorter.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 4: Get results&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Once you have your model fitted, you can get the results to check whether the model works satisfactorily and interpret it.&lt;/p&gt;
&lt;p&gt;You can obtain the coefficient of determination (𝑅²) with &lt;code&gt;.score()&lt;/code&gt; called on &lt;code&gt;model&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight python pycon&quot;&gt;&lt;span class=&quot;repl-toggle&quot; title=&quot;Toggle REPL prompts and output&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;r_sq&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;score&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;coefficient of determination:&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;r_sq&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;coefficient of determination: 0.715875613747954&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;When you&amp;rsquo;re applying &lt;code&gt;.score()&lt;/code&gt;, the arguments are also the predictor &lt;code&gt;x&lt;/code&gt; and regressor &lt;code&gt;y&lt;/code&gt;, and the return value is 𝑅².&lt;/p&gt;
&lt;p&gt;The attributes of &lt;code&gt;model&lt;/code&gt; are &lt;code&gt;.intercept_&lt;/code&gt;, which represents the coefficient, 𝑏₀ and &lt;code&gt;.coef_&lt;/code&gt;, which represents 𝑏₁:&lt;/p&gt;
&lt;div class=&quot;highlight python pycon&quot;&gt;&lt;span class=&quot;repl-toggle&quot; title=&quot;Toggle REPL prompts and output&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;intercept:&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;intercept_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;intercept: 5.633333333333329&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;slope:&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;coef_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;slope: [0.54]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The code above illustrates how to get 𝑏₀ and 𝑏₁. You can notice that &lt;code&gt;.intercept_&lt;/code&gt; is a scalar, while &lt;code&gt;.coef_&lt;/code&gt; is an array.&lt;/p&gt;
&lt;p&gt;The value 𝑏₀ = 5.63 (approximately) illustrates that your model predicts the response 5.63 when 𝑥 is zero. The value 𝑏₁ = 0.54 means that the predicted response rises by 0.54 when 𝑥 is increased by one.&lt;/p&gt;
&lt;p&gt;You should notice that you can provide &lt;code&gt;y&lt;/code&gt; as a two-dimensional array as well. In this case, you&amp;rsquo;ll get a similar result. This is how it might look:&lt;/p&gt;
&lt;div class=&quot;highlight python pycon&quot;&gt;&lt;span class=&quot;repl-toggle&quot; title=&quot;Toggle REPL prompts and output&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new_model&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LinearRegression&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;reshape&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)))&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;intercept:&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;new_model&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;intercept_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;intercept: [5.63333333]&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;slope:&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;new_model&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;coef_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;slope: [[0.54]]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;As you can see, this example is very similar to the previous one, but in this case, &lt;code&gt;.intercept_&lt;/code&gt; is a one-dimensional array with the single element 𝑏₀, and &lt;code&gt;.coef_&lt;/code&gt; is a two-dimensional array with the single element 𝑏₁.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 5: Predict response&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Once there is a satisfactory model, you can use it for predictions with either existing or new data.&lt;/p&gt;
&lt;p&gt;To obtain the predicted response, use &lt;code&gt;.predict()&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight python pycon&quot;&gt;&lt;span class=&quot;repl-toggle&quot; title=&quot;Toggle REPL prompts and output&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y_pred&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;predict&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;predicted response:&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y_pred&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sep&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;predicted response:&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;[ 8.33333333 13.73333333 19.13333333 24.53333333 29.93333333 35.33333333]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;When applying &lt;code&gt;.predict()&lt;/code&gt;, you pass the regressor as the argument and get the corresponding predicted response.&lt;/p&gt;
&lt;p&gt;This is a nearly identical way to predict the response:&lt;/p&gt;
&lt;div class=&quot;highlight python pycon&quot;&gt;&lt;span class=&quot;repl-toggle&quot; title=&quot;Toggle REPL prompts and output&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y_pred&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;intercept_&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;coef_&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;predicted response:&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y_pred&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sep&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;predicted response:&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;[[ 8.33333333]&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt; [13.73333333]&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt; [19.13333333]&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt; [24.53333333]&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt; [29.93333333]&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt; [35.33333333]]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In this case, you multiply each element of &lt;code&gt;x&lt;/code&gt; with &lt;code&gt;model.coef_&lt;/code&gt; and add &lt;code&gt;model.intercept_&lt;/code&gt; to the product.&lt;/p&gt;
&lt;p&gt;The output here differs from the previous example only in dimensions. The predicted response is now a two-dimensional array, while in the previous case, it had one dimension.&lt;/p&gt;
&lt;p&gt;If you reduce the number of dimensions of &lt;code&gt;x&lt;/code&gt; to one, these two approaches will yield the same result. You can do this by replacing &lt;code&gt;x&lt;/code&gt; with &lt;code&gt;x.reshape(-1)&lt;/code&gt;, &lt;code&gt;x.flatten()&lt;/code&gt;, or &lt;code&gt;x.ravel()&lt;/code&gt; when multiplying it with &lt;code&gt;model.coef_&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;In practice, regression models are often applied for forecasts. This means that you can use fitted models to calculate the outputs based on some other, new inputs:&lt;/p&gt;
&lt;div class=&quot;highlight python pycon&quot;&gt;&lt;span class=&quot;repl-toggle&quot; title=&quot;Toggle REPL prompts and output&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x_new&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;arange&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;reshape&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x_new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;[[0]&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt; [1]&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt; [2]&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt; [3]&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt; [4]]&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y_new&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;predict&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x_new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y_new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;[5.63333333 6.17333333 6.71333333 7.25333333 7.79333333]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Here &lt;code&gt;.predict()&lt;/code&gt; is applied to the new regressor &lt;code&gt;x_new&lt;/code&gt; and yields the response &lt;code&gt;y_new&lt;/code&gt;. This example conveniently uses &lt;code&gt;arange()&lt;/code&gt; from &lt;code&gt;numpy&lt;/code&gt; to generate an array with the elements from 0 (inclusive) to 5 (exclusive), that is &lt;code&gt;0&lt;/code&gt;, &lt;code&gt;1&lt;/code&gt;, &lt;code&gt;2&lt;/code&gt;, &lt;code&gt;3&lt;/code&gt;, and &lt;code&gt;4&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;You can find more information about &lt;code&gt;LinearRegression&lt;/code&gt; on &lt;a href=&quot;https://scikit-learn.org/stable/modules/generated/sklearn.linear_model.LinearRegression.html&quot;&gt;the official documentation page&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;multiple-linear-regression-with-scikit-learn&quot;&gt;Multiple Linear Regression With scikit-learn&lt;/h3&gt;
&lt;p&gt;You can implement multiple linear regression following the same steps as you would for simple regression.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Steps 1 and 2: Import packages and classes, and provide data&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;First, you import &lt;code&gt;numpy&lt;/code&gt; and &lt;code&gt;sklearn.linear_model.LinearRegression&lt;/code&gt; and provide known inputs and output:&lt;/p&gt;
&lt;div class=&quot;highlight python&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;numpy&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;np&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;sklearn.linear_model&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LinearRegression&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;15&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;25&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;35&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;11&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;45&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;15&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;55&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;34&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;60&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;35&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]]&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;14&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;22&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;38&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;43&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;That&amp;rsquo;s a simple way to define the input &lt;code&gt;x&lt;/code&gt; and output &lt;code&gt;y&lt;/code&gt;. You can print &lt;code&gt;x&lt;/code&gt; and &lt;code&gt;y&lt;/code&gt; to see how they look now:&lt;/p&gt;
&lt;div class=&quot;highlight python pycon&quot;&gt;&lt;span class=&quot;repl-toggle&quot; title=&quot;Toggle REPL prompts and output&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;[[ 0  1]&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt; [ 5  1]&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt; [15  2]&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt; [25  5]&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt; [35 11]&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt; [45 15]&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt; [55 34]&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt; [60 35]]&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;[ 4  5 20 14 32 22 38 43]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In multiple linear regression, &lt;code&gt;x&lt;/code&gt; is a two-dimensional array with at least two columns, while &lt;code&gt;y&lt;/code&gt; is usually a one-dimensional array. This is a simple example of multiple linear regression, and &lt;code&gt;x&lt;/code&gt; has exactly two columns.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 3: Create a model and fit it&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The next step is to create the regression model as an instance of &lt;code&gt;LinearRegression&lt;/code&gt; and fit it with &lt;code&gt;.fit()&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight python&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;model&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LinearRegression&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The result of this statement is the variable &lt;code&gt;model&lt;/code&gt; referring to the object of type &lt;code&gt;LinearRegression&lt;/code&gt;. It represents the regression model fitted with existing data.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 4: Get results&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;You can obtain the properties of the model the same way as in the case of simple linear regression:&lt;/p&gt;
&lt;div class=&quot;highlight python pycon&quot;&gt;&lt;span class=&quot;repl-toggle&quot; title=&quot;Toggle REPL prompts and output&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;r_sq&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;score&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;coefficient of determination:&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;r_sq&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;coefficient of determination: 0.8615939258756776&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;intercept:&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;intercept_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;intercept: 5.52257927519819&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;slope:&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;coef_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;slope: [0.44706965 0.25502548]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You obtain the value of 𝑅² using &lt;code&gt;.score()&lt;/code&gt; and the values of the estimators of regression coefficients with &lt;code&gt;.intercept_&lt;/code&gt; and &lt;code&gt;.coef_&lt;/code&gt;. Again, &lt;code&gt;.intercept_&lt;/code&gt; holds the bias 𝑏₀, while now &lt;code&gt;.coef_&lt;/code&gt; is an array containing 𝑏₁ and 𝑏₂ respectively.&lt;/p&gt;
&lt;p&gt;In this example, the intercept is approximately 5.52, and this is the value of the predicted response when 𝑥₁ = 𝑥₂ = 0. The increase of 𝑥₁ by 1 yields the rise of the predicted response by 0.45. Similarly, when 𝑥₂ grows by 1, the response rises by 0.26.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 5: Predict response&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Predictions also work the same way as in the case of simple linear regression:&lt;/p&gt;
&lt;div class=&quot;highlight python pycon&quot;&gt;&lt;span class=&quot;repl-toggle&quot; title=&quot;Toggle REPL prompts and output&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y_pred&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;predict&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;predicted response:&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y_pred&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sep&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;predicted response:&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;[ 5.77760476  8.012953   12.73867497 17.9744479  23.97529728 29.4660957&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt; 38.78227633 41.27265006]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The predicted response is obtained with &lt;code&gt;.predict()&lt;/code&gt;, which is very similar to the following:&lt;/p&gt;
&lt;div class=&quot;highlight python pycon&quot;&gt;&lt;span class=&quot;repl-toggle&quot; title=&quot;Toggle REPL prompts and output&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y_pred&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;intercept_&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sum&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;coef_&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;axis&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;predicted response:&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y_pred&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sep&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;predicted response:&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;[ 5.77760476  8.012953   12.73867497 17.9744479  23.97529728 29.4660957&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt; 38.78227633 41.27265006]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You can predict the output values by multiplying each column of the input with the appropriate weight, summing the results and adding the intercept to the sum.&lt;/p&gt;
&lt;p&gt;You can apply this model to new data as well:&lt;/p&gt;
&lt;div class=&quot;highlight python pycon&quot;&gt;&lt;span class=&quot;repl-toggle&quot; title=&quot;Toggle REPL prompts and output&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x_new&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;arange&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;reshape&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x_new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;[[0 1]&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt; [2 3]&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt; [4 5]&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt; [6 7]&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt; [8 9]]&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y_new&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;predict&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x_new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y_new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;[ 5.77760476  7.18179502  8.58598528  9.99017554 11.3943658 ]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;That&amp;rsquo;s the prediction using a linear regression model.&lt;/p&gt;
&lt;h3 id=&quot;polynomial-regression-with-scikit-learn&quot;&gt;Polynomial Regression With scikit-learn&lt;/h3&gt;
&lt;p&gt;Implementing polynomial regression with scikit-learn is very similar to linear regression. There is only one extra step: you need to transform the array of inputs to include non-linear terms such as 𝑥².&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 1: Import packages and classes&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;In addition to &lt;code&gt;numpy&lt;/code&gt; and &lt;code&gt;sklearn.linear_model.LinearRegression&lt;/code&gt;, you should also import the class &lt;code&gt;PolynomialFeatures&lt;/code&gt; from &lt;code&gt;sklearn.preprocessing&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight python&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;numpy&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;np&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;sklearn.linear_model&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LinearRegression&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;sklearn.preprocessing&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PolynomialFeatures&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The import is now done, and you have everything you need to work with.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 2a: Provide data&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;This step defines the input and output and is the same as in the case of linear regression:&lt;/p&gt;
&lt;div class=&quot;highlight python&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;15&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;25&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;35&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;45&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;55&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;reshape&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;15&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;11&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;25&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now you have the input and output in a suitable format. Keep in mind that you need the input to be a &lt;strong&gt;two-dimensional array&lt;/strong&gt;. That&amp;rsquo;s why &lt;code&gt;.reshape()&lt;/code&gt; is used.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 2b: Transform input data&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;This is the &lt;strong&gt;new step&lt;/strong&gt; you need to implement for polynomial regression!&lt;/p&gt;
&lt;p&gt;As you&amp;rsquo;ve seen earlier, you need to include 𝑥² (and perhaps other terms) as additional features when implementing polynomial regression. For that reason, you should transform the input array &lt;code&gt;x&lt;/code&gt; to contain the additional column(s) with the values of 𝑥² (and eventually more features).&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s possible to transform the input array in several ways (like using &lt;code&gt;insert()&lt;/code&gt; from &lt;code&gt;numpy&lt;/code&gt;), but the class &lt;code&gt;PolynomialFeatures&lt;/code&gt; is very convenient for this purpose. Let&amp;rsquo;s create an instance of this class:&lt;/p&gt;
&lt;div class=&quot;highlight python&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;transformer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PolynomialFeatures&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;degree&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;include_bias&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;False&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The variable &lt;code&gt;transformer&lt;/code&gt; refers to an instance of &lt;code&gt;PolynomialFeatures&lt;/code&gt; which you can use to transform the input &lt;code&gt;x&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;You can provide several optional parameters to &lt;code&gt;PolynomialFeatures&lt;/code&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;degree&lt;/code&gt;&lt;/strong&gt; is an integer (&lt;code&gt;2&lt;/code&gt; by default) that represents the degree of the polynomial regression function.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;interaction_only&lt;/code&gt;&lt;/strong&gt; is a Boolean (&lt;code&gt;False&lt;/code&gt; by default) that decides whether to include only interaction features (&lt;code&gt;True&lt;/code&gt;) or all features (&lt;code&gt;False&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;include_bias&lt;/code&gt;&lt;/strong&gt; is a Boolean (&lt;code&gt;True&lt;/code&gt; by default) that decides whether to include the bias (intercept) column of ones (&lt;code&gt;True&lt;/code&gt;) or not (&lt;code&gt;False&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This example uses the default values of all parameters, but you&amp;rsquo;ll sometimes want to experiment with the degree of the function, and it can be beneficial to provide this argument anyway.&lt;/p&gt;
&lt;p&gt;Before applying &lt;code&gt;transformer&lt;/code&gt;, you need to fit it with &lt;code&gt;.fit()&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight python&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;transformer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Once &lt;code&gt;transformer&lt;/code&gt; is fitted, it&amp;rsquo;s ready to create a new, modified input. You apply &lt;code&gt;.transform()&lt;/code&gt; to do that:&lt;/p&gt;
&lt;div class=&quot;highlight python&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x_&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;transformer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;transform&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;That&amp;rsquo;s the transformation of the input array with &lt;code&gt;.transform()&lt;/code&gt;. It takes the input array as the argument and returns the modified array.&lt;/p&gt;
&lt;p&gt;You can also use &lt;code&gt;.fit_transform()&lt;/code&gt; to replace the three previous statements with only one:&lt;/p&gt;
&lt;div class=&quot;highlight python&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x_&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PolynomialFeatures&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;degree&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;include_bias&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;False&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fit_transform&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;That&amp;rsquo;s fitting and transforming the input array in one statement with &lt;code&gt;.fit_transform()&lt;/code&gt;. It also takes the input array and effectively does the same thing as &lt;code&gt;.fit()&lt;/code&gt; and &lt;code&gt;.transform()&lt;/code&gt; called in that order. It also returns the modified array. This is how the new input array looks:&lt;/p&gt;
&lt;div class=&quot;highlight python pycon&quot;&gt;&lt;span class=&quot;repl-toggle&quot; title=&quot;Toggle REPL prompts and output&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;[[   5.   25.]&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt; [  15.  225.]&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt; [  25.  625.]&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt; [  35. 1225.]&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt; [  45. 2025.]&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt; [  55. 3025.]]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The modified input array contains two columns: one with the original inputs and the other with their squares.&lt;/p&gt;
&lt;p&gt;You can find more information about &lt;code&gt;PolynomialFeatures&lt;/code&gt; on &lt;a href=&quot;https://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.PolynomialFeatures.html&quot;&gt;the official documentation page&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 3: Create a model and fit it&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;This step is also the same as in the case of linear regression. You create and fit the model:&lt;/p&gt;
&lt;div class=&quot;highlight python&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;model&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LinearRegression&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The regression model is now created and fitted. It&amp;rsquo;s ready for application.&lt;/p&gt;
&lt;p&gt;You should keep in mind that the first argument of &lt;code&gt;.fit()&lt;/code&gt; is the &lt;em&gt;modified input array&lt;/em&gt; &lt;code&gt;x_&lt;/code&gt; and not the original &lt;code&gt;x&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 4: Get results&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;You can obtain the properties of the model the same way as in the case of linear regression:&lt;/p&gt;
&lt;div class=&quot;highlight python pycon&quot;&gt;&lt;span class=&quot;repl-toggle&quot; title=&quot;Toggle REPL prompts and output&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;r_sq&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;score&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;coefficient of determination:&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;r_sq&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;coefficient of determination: 0.8908516262498564&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;intercept:&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;intercept_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;intercept: 21.372321428571425&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;coefficients:&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;coef_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;coefficients: [-1.32357143  0.02839286]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Again, &lt;code&gt;.score()&lt;/code&gt; returns 𝑅². Its first argument is also the modified input &lt;code&gt;x_&lt;/code&gt;, not &lt;code&gt;x&lt;/code&gt;. The values of the weights are associated to &lt;code&gt;.intercept_&lt;/code&gt; and &lt;code&gt;.coef_&lt;/code&gt;: &lt;code&gt;.intercept_&lt;/code&gt; represents 𝑏₀, while &lt;code&gt;.coef_&lt;/code&gt; references the array that contains 𝑏₁ and 𝑏₂ respectively.&lt;/p&gt;
&lt;p&gt;You can obtain a very similar result with different transformation and regression arguments:&lt;/p&gt;
&lt;div class=&quot;highlight python&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x_&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PolynomialFeatures&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;degree&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;include_bias&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fit_transform&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;If you call &lt;code&gt;PolynomialFeatures&lt;/code&gt; with the default parameter &lt;code&gt;include_bias=True&lt;/code&gt; (or if you just omit it), you&amp;rsquo;ll obtain the new input array &lt;code&gt;x_&lt;/code&gt; with the additional leftmost column containing only ones. This column corresponds to the intercept. This is how the modified input array looks in this case:&lt;/p&gt;
&lt;div class=&quot;highlight python pycon&quot;&gt;&lt;span class=&quot;repl-toggle&quot; title=&quot;Toggle REPL prompts and output&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;[[1.000e+00 5.000e+00 2.500e+01]&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt; [1.000e+00 1.500e+01 2.250e+02]&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt; [1.000e+00 2.500e+01 6.250e+02]&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt; [1.000e+00 3.500e+01 1.225e+03]&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt; [1.000e+00 4.500e+01 2.025e+03]&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt; [1.000e+00 5.500e+01 3.025e+03]]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The first column of &lt;code&gt;x_&lt;/code&gt; contains ones, the second has the values of &lt;code&gt;x&lt;/code&gt;, while the third holds the squares of &lt;code&gt;x&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The intercept is already included with the leftmost column of ones, and you don&amp;rsquo;t need to include it again when creating the instance of &lt;code&gt;LinearRegression&lt;/code&gt;. Thus, you can provide &lt;code&gt;fit_intercept=False&lt;/code&gt;. This is how the next statement looks:&lt;/p&gt;
&lt;div class=&quot;highlight python&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;model&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LinearRegression&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fit_intercept&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;False&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The variable &lt;code&gt;model&lt;/code&gt; again corresponds to the new input array &lt;code&gt;x_&lt;/code&gt;. Therefore &lt;code&gt;x_&lt;/code&gt; should be passed as the first argument instead of &lt;code&gt;x&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;This approach yields the following results, which are similar to the previous case:&lt;/p&gt;
&lt;div class=&quot;highlight python pycon&quot;&gt;&lt;span class=&quot;repl-toggle&quot; title=&quot;Toggle REPL prompts and output&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;r_sq&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;score&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;coefficient of determination:&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;r_sq&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;coefficient of determination: 0.8908516262498565&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;intercept:&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;intercept_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;intercept: 0.0&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;coefficients:&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;coef_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;coefficients: [21.37232143 -1.32357143  0.02839286]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You see that now &lt;code&gt;.intercept_&lt;/code&gt; is zero, but &lt;code&gt;.coef_&lt;/code&gt; actually contains 𝑏₀ as its first element. Everything else is the same.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 5: Predict response&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;If you want to get the predicted response, just use &lt;code&gt;.predict()&lt;/code&gt;, but remember that the argument should be the modified input &lt;code&gt;x_&lt;/code&gt; instead of the old &lt;code&gt;x&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight python pycon&quot;&gt;&lt;span class=&quot;repl-toggle&quot; title=&quot;Toggle REPL prompts and output&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y_pred&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;predict&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;predicted response:&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y_pred&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sep&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;predicted response:&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;[15.46428571  7.90714286  6.02857143  9.82857143 19.30714286 34.46428571]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;As you can see, the prediction works almost the same way as in the case of linear regression. It just requires the modified input instead of the original.&lt;/p&gt;
&lt;p&gt;You can apply the identical procedure if you have &lt;strong&gt;several input variables&lt;/strong&gt;. You&amp;rsquo;ll have an input array with more than one column, but everything else is the same. Here is an example:&lt;/p&gt;
&lt;div class=&quot;highlight python&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;# Step 1: Import packages&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;numpy&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;np&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;sklearn.linear_model&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LinearRegression&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;sklearn.preprocessing&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PolynomialFeatures&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Step 2a: Provide data&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;15&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;25&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;35&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;11&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;45&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;15&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;55&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;34&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;60&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;35&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]]&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;14&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;22&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;38&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;43&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Step 2b: Transform input data&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;x_&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PolynomialFeatures&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;degree&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;include_bias&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;False&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fit_transform&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Step 3: Create a model and fit it&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;model&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LinearRegression&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Step 4: Get results&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;r_sq&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;score&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;intercept&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;coefficients&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;intercept_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;coef_&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Step 5: Predict&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;y_pred&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;predict&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This regression example yields the following results and predictions:&lt;/p&gt;
&lt;div class=&quot;highlight python pycon&quot;&gt;&lt;span class=&quot;repl-toggle&quot; title=&quot;Toggle REPL prompts and output&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;coefficient of determination:&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;r_sq&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;coefficient of determination: 0.9453701449127822&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;intercept:&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;intercept&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;intercept: 0.8430556452395734&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;coefficients:&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;coefficients&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sep&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;coefficients:&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;[ 2.44828275  0.16160353 -0.15259677  0.47928683 -0.4641851 ]&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;predicted response:&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y_pred&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sep&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;predicted response:&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;[ 0.54047408 11.36340283 16.07809622 15.79139    29.73858619 23.50834636&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt; 39.05631386 41.92339046]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In this case, there are six regression coefficients (including the intercept), as shown in the estimated regression function 𝑓(𝑥₁, 𝑥₂) = 𝑏₀ + 𝑏₁𝑥₁ + 𝑏₂𝑥₂ + 𝑏₃𝑥₁² + 𝑏₄𝑥₁𝑥₂ + 𝑏₅𝑥₂².&lt;/p&gt;
&lt;p&gt;You can also notice that polynomial regression yielded a higher coefficient of determination than multiple linear regression for the same problem. At first, you could think that obtaining such a large 𝑅² is an excellent result. It might be.&lt;/p&gt;
&lt;p&gt;However, in real-world situations, having a complex model and 𝑅² very close to 1 might also be a sign of overfitting. To check the performance of a model, you should test it with new data, that is with observations not used to fit (train) the model.&lt;/p&gt;
&lt;h3 id=&quot;advanced-linear-regression-with-statsmodels&quot;&gt;Advanced Linear Regression With &lt;code&gt;statsmodels&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;You can implement linear regression in Python relatively easily by using the package &lt;code&gt;statsmodels&lt;/code&gt; as well. Typically, this is desirable when there is a need for more detailed results.&lt;/p&gt;
&lt;p&gt;The procedure is similar to that of scikit-learn.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 1: Import packages&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;First you need to do some imports. In addition to &lt;code&gt;numpy&lt;/code&gt;, you need to import &lt;code&gt;statsmodels.api&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight python&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;numpy&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;np&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;statsmodels.api&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;sm&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now you have the packages you need.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 2: Provide data and transform inputs&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;You can provide the inputs and outputs the same way as you did when you were using scikit-learn:&lt;/p&gt;
&lt;div class=&quot;highlight python&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;15&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;25&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;35&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;11&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;45&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;15&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;55&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;34&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;60&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;35&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]]&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;14&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;22&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;38&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;43&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The input and output arrays are created, but the job is not done yet.&lt;/p&gt;
&lt;p&gt;You need to add the column of ones to the inputs if you want &lt;code&gt;statsmodels&lt;/code&gt; to calculate the intercept 𝑏₀. It doesn&amp;rsquo;t takes 𝑏₀ into account by default. This is just one function call:&lt;/p&gt;
&lt;div class=&quot;highlight python&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sm&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add_constant&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;That&amp;rsquo;s how you add the column of ones to &lt;code&gt;x&lt;/code&gt; with &lt;code&gt;add_constant()&lt;/code&gt;. It takes the input array &lt;code&gt;x&lt;/code&gt; as an argument and returns a new array with the column of ones inserted at the beginning. This is how &lt;code&gt;x&lt;/code&gt; and &lt;code&gt;y&lt;/code&gt; look now:&lt;/p&gt;
&lt;div class=&quot;highlight python pycon&quot;&gt;&lt;span class=&quot;repl-toggle&quot; title=&quot;Toggle REPL prompts and output&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;[[ 1.  0.  1.]&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt; [ 1.  5.  1.]&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt; [ 1. 15.  2.]&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt; [ 1. 25.  5.]&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt; [ 1. 35. 11.]&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt; [ 1. 45. 15.]&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt; [ 1. 55. 34.]&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt; [ 1. 60. 35.]]&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;[ 4  5 20 14 32 22 38 43]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You can see that the modified &lt;code&gt;x&lt;/code&gt; has three columns: the first column of ones (corresponding to 𝑏₀ and replacing the intercept) as well as two columns of the original features.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 3: Create a model and fit it&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The regression model based on ordinary least squares is an instance of the class &lt;code&gt;statsmodels.regression.linear_model.OLS&lt;/code&gt;. This is how you can obtain one:&lt;/p&gt;
&lt;div class=&quot;highlight python&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;model&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sm&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;OLS&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You should be careful here! Please, notice that the first argument is the output, followed with the input. There are several more optional parameters.&lt;/p&gt;
&lt;p&gt;To find more information about this class, please visit &lt;a href=&quot;https://www.statsmodels.org/stable/generated/statsmodels.regression.linear_model.OLS.html&quot;&gt;the official documentation page&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Once your model is created, you can apply &lt;code&gt;.fit()&lt;/code&gt; on it:&lt;/p&gt;
&lt;div class=&quot;highlight python&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;results&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;By calling &lt;code&gt;.fit()&lt;/code&gt;, you obtain the variable &lt;code&gt;results&lt;/code&gt;, which is an instance of the class &lt;code&gt;statsmodels.regression.linear_model.RegressionResultsWrapper&lt;/code&gt;. This object holds a lot of information about the regression model.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 4: Get results&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The variable &lt;code&gt;results&lt;/code&gt; refers to the object that contains detailed information about the results of linear regression. Explaining them is far beyond the scope of this article, but you&amp;rsquo;ll learn here how to extract them.&lt;/p&gt;
&lt;p&gt;You can call &lt;code&gt;.summary()&lt;/code&gt; to get the table with the results of linear regression:&lt;/p&gt;
&lt;div class=&quot;highlight python pycon&quot;&gt;&lt;span class=&quot;repl-toggle&quot; title=&quot;Toggle REPL prompts and output&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;results&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;summary&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;OLS Regression Results                            &lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;==============================================================================&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Dep. Variable:                      y   R-squared:                       0.862&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Model:                            OLS   Adj. R-squared:                  0.806&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Method:                 Least Squares   F-statistic:                     15.56&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Date:                Sun, 17 Feb 2019   Prob (F-statistic):            0.00713&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Time:                        19:15:07   Log-Likelihood:                -24.316&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;No. Observations:                   8   AIC:                             54.63&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Df Residuals:                       5   BIC:                             54.87&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Df Model:                           2                                         &lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Covariance Type:            nonrobust                                         &lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;==============================================================================&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;coef    std err          t      P&amp;gt;|t|      [0.025      0.975]&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;------------------------------------------------------------------------------&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;const          5.5226      4.431      1.246      0.268      -5.867      16.912&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;x1             0.4471      0.285      1.567      0.178      -0.286       1.180&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;x2             0.2550      0.453      0.563      0.598      -0.910       1.420&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;==============================================================================&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Omnibus:                        0.561   Durbin-Watson:                   3.268&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Prob(Omnibus):                  0.755   Jarque-Bera (JB):                0.534&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Skew:                           0.380   Prob(JB):                        0.766&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Kurtosis:                       1.987   Cond. No.                         80.1&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;==============================================================================&lt;/span&gt;

&lt;span class=&quot;go&quot;&gt;Warnings:&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;[1] Standard Errors assume that the covariance matrix of the errors is correctly specified.&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This table is very comprehensive. You can find many statistical values associated with linear regression including 𝑅², 𝑏₀, 𝑏₁, and 𝑏₂.&lt;/p&gt;
&lt;p&gt;In this particular case, you might obtain the warning related to &lt;code&gt;kurtosistest&lt;/code&gt;. This is due to the small number of observations provided.&lt;/p&gt;
&lt;p&gt;You can extract any of the values from the table above. Here&amp;rsquo;s an example:&lt;/p&gt;
&lt;div class=&quot;highlight python pycon&quot;&gt;&lt;span class=&quot;repl-toggle&quot; title=&quot;Toggle REPL prompts and output&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;coefficient of determination:&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;results&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rsquared&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;coefficient of determination: 0.8615939258756777&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;adjusted coefficient of determination:&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;results&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rsquared_adj&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;adjusted coefficient of determination: 0.8062314962259488&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;regression coefficients:&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;results&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;params&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;regression coefficients: [5.52257928 0.44706965 0.25502548]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;That&amp;rsquo;s how you obtain some of the results of linear regression:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;.rsquared&lt;/code&gt;&lt;/strong&gt; holds 𝑅².&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;.rsquared_adj&lt;/code&gt;&lt;/strong&gt; represents adjusted 𝑅² (𝑅² corrected according to the number of input features).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;.params&lt;/code&gt;&lt;/strong&gt; refers the array with 𝑏₀, 𝑏₁, and 𝑏₂ respectively.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;You can also notice that these results are identical to those obtained with scikit-learn for the same problem.&lt;/p&gt;
&lt;p&gt;To find more information about the results of linear regression, please visit &lt;a href=&quot;https://www.statsmodels.org/stable/generated/statsmodels.regression.linear_model.RegressionResults.html&quot;&gt;the official documentation page&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 5: Predict response&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;You can obtain the predicted response on the input values used for creating the model using &lt;code&gt;.fittedvalues&lt;/code&gt; or &lt;code&gt;.predict()&lt;/code&gt; with the input array as the argument:&lt;/p&gt;
&lt;div class=&quot;highlight python pycon&quot;&gt;&lt;span class=&quot;repl-toggle&quot; title=&quot;Toggle REPL prompts and output&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;predicted response:&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;results&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fittedvalues&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sep&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;predicted response:&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;[ 5.77760476  8.012953   12.73867497 17.9744479  23.97529728 29.4660957&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt; 38.78227633 41.27265006]&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;predicted response:&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;results&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;predict&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sep&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;predicted response:&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;[ 5.77760476  8.012953   12.73867497 17.9744479  23.97529728 29.4660957&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt; 38.78227633 41.27265006]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This is the predicted response for known inputs. If you want predictions with new regressors, you can also apply &lt;code&gt;.predict()&lt;/code&gt; with new data as the argument:&lt;/p&gt;
&lt;div class=&quot;highlight python pycon&quot;&gt;&lt;span class=&quot;repl-toggle&quot; title=&quot;Toggle REPL prompts and output&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x_new&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sm&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add_constant&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;arange&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;reshape&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)))&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x_new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;[[1. 0. 1.]&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt; [1. 2. 3.]&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt; [1. 4. 5.]&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt; [1. 6. 7.]&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt; [1. 8. 9.]]&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y_new&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;results&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;predict&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x_new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y_new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;[ 5.77760476  7.18179502  8.58598528  9.99017554 11.3943658 ]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You can notice that the predicted results are the same as those obtained with scikit-learn for the same problem.&lt;/p&gt;
&lt;h2 id=&quot;beyond-linear-regression&quot;&gt;Beyond Linear Regression&lt;/h2&gt;
&lt;p&gt;Linear regression is sometimes not appropriate, especially for non-linear models of high complexity.&lt;/p&gt;
&lt;p&gt;Fortunately, there are other regression techniques suitable for the cases where linear regression doesn&amp;rsquo;t work well. Some of them are support vector machines, decision trees, random forest, and neural networks.&lt;/p&gt;
&lt;p&gt;There are numerous Python libraries for regression using these techniques. Most of them are free and open-source. That&amp;rsquo;s one of the reasons why Python is among the main programming languages for machine learning.&lt;/p&gt;
&lt;p&gt;The package scikit-learn provides the means for using other regression techniques in a very similar way to what you&amp;rsquo;ve seen. It contains the classes for support vector machines, decision trees, random forest, and more, with the methods &lt;code&gt;.fit()&lt;/code&gt;, &lt;code&gt;.predict()&lt;/code&gt;, &lt;code&gt;.score()&lt;/code&gt; and so on.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;You now know what linear regression is and how you can implement it with Python and three open-source packages: NumPy, scikit-learn, and &lt;code&gt;statsmodels&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;You use NumPy for handling arrays.&lt;/p&gt;
&lt;p&gt;Linear regression is implemented with the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;scikit-learn&lt;/strong&gt; if you don&amp;rsquo;t need detailed results and want to use the approach consistent with other regression techniques&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;statsmodels&lt;/strong&gt; if you need the advanced statistical parameters of a model&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Both approaches are worth learning how to use and exploring further. The links in this article can be very useful for that.&lt;/p&gt;
&lt;p&gt;When performing linear regression in Python, you can follow these steps:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Import the packages and classes you need&lt;/li&gt;
&lt;li&gt;Provide data to work with and eventually do appropriate transformations&lt;/li&gt;
&lt;li&gt;Create a regression model and fit it with existing data&lt;/li&gt;
&lt;li&gt;Check the results of model fitting to know whether the model is satisfactory&lt;/li&gt;
&lt;li&gt;Apply the model for predictions&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;If you have questions or comments, please put them in the comment section below.&lt;/p&gt;
        &lt;hr /&gt;
        &lt;p&gt;&lt;em&gt;[ Improve Your Python With 🐍 Python Tricks 💌 – Get a short &amp;amp; sweet Python Trick delivered to your inbox every couple of days. &lt;a href=&quot;https://realpython.com/python-tricks/?utm_source=realpython&amp;amp;utm_medium=rss&amp;amp;utm_campaign=footer&quot;&gt;&amp;gt;&amp;gt; Click here to learn more and see examples&lt;/a&gt; ]&lt;/em&gt;&lt;/p&gt;
      </content>
    </entry>
  
    <entry>
      <title>Python String Formatting Tips &amp; Best Practices</title>
      <id>https://realpython.com/courses/python-string-formatting-tips-best-practices/</id>
      <link href="https://realpython.com/courses/python-string-formatting-tips-best-practices/"/>
      <updated>2019-04-11T14:00:00+00:00</updated>
      <summary>Learn the four main approaches to string formatting in Python, as well as their strengths and weaknesses. You&#39;ll also get a simple rule of thumb for how to pick the best general purpose string formatting approach in your own programs.</summary>
      <content type="html">
        &lt;p&gt;Learn the four main approaches to string formatting in Python, as well as their strengths and weaknesses. You&amp;rsquo;ll also get a simple rule of thumb for how to pick the best general purpose string formatting approach in your own programs.&lt;/p&gt;
        &lt;hr /&gt;
        &lt;p&gt;&lt;em&gt;[ Improve Your Python With 🐍 Python Tricks 💌 – Get a short &amp;amp; sweet Python Trick delivered to your inbox every couple of days. &lt;a href=&quot;https://realpython.com/python-tricks/?utm_source=realpython&amp;amp;utm_medium=rss&amp;amp;utm_campaign=footer&quot;&gt;&amp;gt;&amp;gt; Click here to learn more and see examples&lt;/a&gt; ]&lt;/em&gt;&lt;/p&gt;
      </content>
    </entry>
  
    <entry>
      <title>How to Create an Index in Django Without Downtime</title>
      <id>https://realpython.com/create-django-index-without-downtime/</id>
      <link href="https://realpython.com/create-django-index-without-downtime/"/>
      <updated>2019-04-10T14:00:00+00:00</updated>
      <summary>In this step-by-step Python tutorial, you&#39;ll get a solid understanding of the limitations of Django migrations by tackling a well known problem: creating an index in Django with no downtime.</summary>
      <content type="html">
        &lt;p&gt;Managing database migrations is a great challenge in any software project. Luckily, as of version 1.7, Django comes with a built-in migration framework. The framework is very powerful and useful in managing change in databases. But the flexibility provided by the framework required some compromises. To understand the limitations of Django migrations, you are going to tackle a well known problem: creating an index in Django with no downtime.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;In this tutorial, you&amp;rsquo;ll learn:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;How and when Django generates new migrations&lt;/li&gt;
&lt;li&gt;How to inspect the commands Django generates to execute migrations&lt;/li&gt;
&lt;li&gt;How to safely modify migrations to fit your needs&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This intermediate-level tutorial is designed for readers who are already familiar with Django migrations. For an introduction to that topic, check out &lt;a href=&quot;https://realpython.com/django-migrations-a-primer/&quot;&gt;Django Migrations: A Primer&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;alert alert-warning&quot; role=&quot;alert&quot;&gt;&lt;p&gt;&lt;strong&gt;Free Bonus:&lt;/strong&gt; &lt;a href=&quot;&quot; class=&quot;alert-link&quot; data-toggle=&quot;modal&quot; data-target=&quot;#modal-django-resources-2&quot; data-focus=&quot;false&quot;&gt;Click here to get free access to additional Django tutorials and resources&lt;/a&gt; you can use to deepen your Python web development skills.&lt;/p&gt;&lt;/div&gt;

&lt;h2 id=&quot;the-problem-with-creating-an-index-in-django-migrations&quot;&gt;The Problem With Creating an Index in Django Migrations&lt;/h2&gt;
&lt;p&gt;A common change that usually becomes necessary when the data stored by your application grows is adding an index. Indexes are used to speed up queries and make your app feel fast and responsive.&lt;/p&gt;
&lt;p&gt;In most databases, adding an index requires an exclusive lock on the table. An exclusive lock prevents data modification (DML) operations such as &lt;code&gt;UPDATE&lt;/code&gt;, &lt;code&gt;INSERT&lt;/code&gt;, and &lt;code&gt;DELETE&lt;/code&gt;, while the index is created.&lt;/p&gt;
&lt;p&gt;Locks are obtained implicitly by the database when executing certain operations. For example, when a user logs into your app, Django will update the &lt;code&gt;last_login&lt;/code&gt; field in the &lt;code&gt;auth_user&lt;/code&gt; table. To perform the update, the database will first have to obtain a lock on the row. If the row is currently being locked by another connection, then you might get a &lt;a href=&quot;https://docs.djangoproject.com/en/2.1/ref/exceptions/#database-exceptions&quot;&gt;database exception&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Locking a table might pose a problem when it&amp;rsquo;s necessary to keep the system available during migrations. The bigger the table, the longer it can take to create the index. The longer it takes to create the index, the longer the system is unavailable or unresponsive to users.&lt;/p&gt;
&lt;p&gt;Some database vendors provide a way to create an index without locking the table. For example, to create an index in PostgreSQL without locking a table, you can use the &lt;a href=&quot;https://www.postgresql.org/docs/current/sql-createindex.html&quot;&gt;&lt;code&gt;CONCURRENTLY&lt;/code&gt;&lt;/a&gt; keyword:&lt;/p&gt;
&lt;div class=&quot;highlight sql&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;INDEX&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CONCURRENTLY&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ix&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;ON&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;table&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;column&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In Oracle, there is an &lt;a href=&quot;https://docs.oracle.com/en/database/oracle/oracle-database/18/sqlrf/CREATE-INDEX.html&quot;&gt;&lt;code&gt;ONLINE&lt;/code&gt;&lt;/a&gt; option to allow DML operations on the table while the index is created:&lt;/p&gt;
&lt;div class=&quot;highlight sql&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;INDEX&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ix&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;ON&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;table&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;column&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ONLINE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;When generating migrations, Django will not use these special keywords. Running the migration as is will make the database acquire an exclusive lock on the table and prevent DML operations while the index is created.&lt;/p&gt;
&lt;p&gt;Creating an index concurrently has some caveats. It&amp;rsquo;s important to understand the issues specific to your database backend in advance. For example, &lt;a href=&quot;https://www.postgresql.org/docs/current/sql-createindex.html#SQL-CREATEINDEX-CONCURRENTLY&quot;&gt;one caveat in PostgreSQL&lt;/a&gt; is that creating an index concurrently takes longer because it requires an additional table scan.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;In this tutorial, you&amp;rsquo;ll use Django migrations to create an index on a large table, without causing any downtime.&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;alert alert-primary&quot; role=&quot;alert&quot;&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; To follow this tutorial, it is recommended that you use a PostgreSQL backend, Django 2.x, and Python 3.&lt;/p&gt;
&lt;p&gt;It is possible to follow along with other database backends as well. In places where SQL features unique to PostgreSQL are used, change the SQL to match your database backend.&lt;/p&gt;
&lt;/div&gt;
&lt;h2 id=&quot;setup&quot;&gt;Setup&lt;/h2&gt;
&lt;p&gt;You&amp;rsquo;re going to use a made up &lt;code&gt;Sale&lt;/code&gt; model in an app called &lt;code&gt;app&lt;/code&gt;. In a real life situation, models such as &lt;code&gt;Sale&lt;/code&gt; are the main tables in the database, and they will usually be very big and store a lot of data:&lt;/p&gt;
&lt;div class=&quot;highlight python&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;# models.py&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;django.db&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;models&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Sale&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;models&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;sold_at&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;models&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;DateTimeField&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;auto_now_add&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;charged_amount&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;models&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;PositiveIntegerField&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;To create the table, generate the initial migration and apply it:&lt;/p&gt;
&lt;div class=&quot;highlight sh&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; python manage.py makemigrations
&lt;span class=&quot;go&quot;&gt;Migrations for &amp;#39;app&amp;#39;:&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  app/migrations/0001_initial.py&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;    - Create model Sale&lt;/span&gt;

&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; python manage migrate
&lt;span class=&quot;go&quot;&gt;Operations to perform:&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  Apply all migrations: app&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Running migrations:&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  Applying app.0001_initial... OK&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;After a while, the sales table becomes very big, and users start to complain about slowness. While monitoring the database, you noticed that a lot of queries use the &lt;code&gt;sold_at&lt;/code&gt; column. To speed things up, you decide that you need an index on the column.&lt;/p&gt;
&lt;p&gt;To add an index on &lt;code&gt;sold_at&lt;/code&gt;, you make the following change to the model:&lt;/p&gt;
&lt;div class=&quot;highlight python&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;# models.py&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;django.db&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;models&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Sale&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;models&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;sold_at&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;models&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;DateTimeField&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;auto_now_add&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;hll&quot;&gt;        &lt;span class=&quot;n&quot;&gt;db_index&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;/span&gt;    &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;charged_amount&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;models&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;PositiveIntegerField&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;If you run this migration as it is, then Django will create the index on the table, and it will be locked until the index is completed. It can take a while to create an index on a very large table, and you want to avoid downtime.&lt;/p&gt;
&lt;p&gt;On a local development environment with a small dataset and very few connections, this migration might feel instantaneous. However, on large datasets with many concurrent connections, obtaining a lock and creating the index can take a while.&lt;/p&gt;
&lt;p&gt;In the next steps, you are going to modify migrations created by Django to create the index without causing any downtime.&lt;/p&gt;
&lt;h2 id=&quot;fake-migration&quot;&gt;Fake Migration&lt;/h2&gt;
&lt;p&gt;The first approach is to create the index manually. You are going to generate the migration, but you are not going to actually let Django apply it. Instead, you will run the SQL manually in the database and then make Django think the migration completed.&lt;/p&gt;
&lt;p&gt;First, generate the migration:&lt;/p&gt;
&lt;div class=&quot;highlight sh&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; python manage.py makemigrations --name add_index_fake
&lt;span class=&quot;go&quot;&gt;Migrations for &amp;#39;app&amp;#39;:&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  app/migrations/0002_add_index_fake.py&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;    - Alter field sold_at on sale&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Use the &lt;a href=&quot;https://docs.djangoproject.com/en/2.1/ref/django-admin/#django-admin-sqlmigrate&quot;&gt;&lt;code&gt;sqlmigrate&lt;/code&gt; command&lt;/a&gt; to view the SQL Django will use to execute this migration:&lt;/p&gt;
&lt;div class=&quot;highlight sh&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; python manage.py sqlmigrate app &lt;span class=&quot;m&quot;&gt;0002&lt;/span&gt;

&lt;span class=&quot;go&quot;&gt;BEGIN;&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;--&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;-- Alter field sold_at on sale&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;--&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;CREATE INDEX &amp;quot;app_sale_sold_at_b9438ae4&amp;quot; ON &amp;quot;app_sale&amp;quot; (&amp;quot;sold_at&amp;quot;);&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;COMMIT;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You want to create the index without locking the table, so you need to modify the command. Add the &lt;code&gt;CONCURRENTLY&lt;/code&gt; keyword and execute in the database:&lt;/p&gt;
&lt;div class=&quot;highlight psql&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;app=#&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;INDEX&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;CONCURRENTLY&lt;/span&gt; &lt;span class=&quot;s s-Name&quot;&gt;&amp;quot;app_sale_sold_at_b9438ae4&amp;quot;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;ON&lt;/span&gt; &lt;span class=&quot;s s-Name&quot;&gt;&amp;quot;app_sale&amp;quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s s-Name&quot;&gt;&amp;quot;sold_at&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;go&quot;&gt;CREATE INDEX&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Notice that you executed the command without the &lt;code&gt;BEGIN&lt;/code&gt; and &lt;code&gt;COMMIT&lt;/code&gt; parts. Omitting these keywords will execute the commands without a database transaction. We will discuss database transactions later in the article.&lt;/p&gt;
&lt;p&gt;After you executed the command, if you try to apply migrations, then you will get the following error:&lt;/p&gt;
&lt;div class=&quot;highlight sh&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; python manage.py migrate

&lt;span class=&quot;go&quot;&gt;Operations to perform:&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  Apply all migrations: app&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Running migrations:&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  Applying app.0002_add_index_fake...Traceback (most recent call last):&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  File &amp;quot;venv/lib/python3.7/site-packages/django/db/backends/utils.py&amp;quot;, line 85, in _execute&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;    return self.cursor.execute(sql, params)&lt;/span&gt;

&lt;span class=&quot;hll&quot;&gt;&lt;span class=&quot;go&quot;&gt;psycopg2.ProgrammingError: relation &amp;quot;app_sale_sold_at_b9438ae4&amp;quot; already exists&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Django complains that the index already exists, so it can&amp;rsquo;t proceed with the migration. You just created the index directly in the database, so now you need to make Django think that the migration was already applied.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;How to Fake a Migration&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Django provides a built-in way of marking migrations as executed, without actually executing them. To use this option, set the &lt;code&gt;--fake&lt;/code&gt; flag when applying the migration:&lt;/p&gt;
&lt;div class=&quot;highlight sh&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; python manage.py migrate --fake
&lt;span class=&quot;go&quot;&gt;Operations to perform:&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  Apply all migrations: app&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Running migrations:&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  Applying app.0002_add_index_fake... FAKED&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Django didn&amp;rsquo;t raise an error this time. In fact, Django didn&amp;rsquo;t really apply any migration. It just marked it as executed (or &lt;code&gt;FAKED&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;Here are some issues to consider when faking migrations:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;The manual command must be equivalent to the SQL generated by Django:&lt;/strong&gt; You need to make sure the command you execute is equivalent to the SQL generated by Django. Use &lt;code&gt;sqlmigrate&lt;/code&gt; to produce the SQL command. If the commands do not match, then you might end up with inconsistencies between the database and the models state.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Other unapplied migrations will also be faked:&lt;/strong&gt; When you have multiple unapplied migrations, they will all be faked. Before you apply migrations, it&amp;rsquo;s important to make sure only the migrations you want to fake are unapplied. Otherwise, you might end up with inconsistencies. Another option is to specify the exact migration you want to fake.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Direct access to the database is required:&lt;/strong&gt; You need to run the SQL command in the database. This is not always an option. Also, executing commands directly in a production database is dangerous and should be avoided when possible.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Automated deployment processes might need adjustments:&lt;/strong&gt; If you &lt;a href=&quot;https://realpython.com/automating-django-deployments-with-fabric-and-ansible/&quot;&gt;automated the deployment process&lt;/a&gt; (using CI, CD, or other automation tools), then you might need to alter the process to fake migrations. This is not always desirable.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Cleanup&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Before moving on to the next section, you need to bring the database back to its state right after the initial migration. To do that, migrate back to the initial migration:&lt;/p&gt;
&lt;div class=&quot;highlight sh&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; python manage.py migrate &lt;span class=&quot;m&quot;&gt;0001&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Operations to perform:&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  Target specific migration: 0001_initial, from app&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Running migrations:&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  Rendering model states... DONE&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  Unapplying app.0002_add_index_fake... OK&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Django unapplied the changes made in the second migration, so now it&amp;rsquo;s safe to also delete the file:&lt;/p&gt;
&lt;div class=&quot;highlight sh&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; rm app/migrations/0002_add_index_fake.py
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;To make sure you did everything right, inspect the migrations:&lt;/p&gt;
&lt;div class=&quot;highlight sh&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; python manage.py showmigrations app
&lt;span class=&quot;go&quot;&gt;app&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt; [X] 0001_initial&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The initial migration was applied, and there are no unapplied migrations.&lt;/p&gt;
&lt;h2 id=&quot;execute-raw-sql-in-migrations&quot;&gt;Execute Raw SQL in Migrations&lt;/h2&gt;
&lt;p&gt;In the previous section, you executed SQL directly in the database and faked the migration. This gets the job done, but there is a better solution.&lt;/p&gt;
&lt;p&gt;Django provides a way to execute raw SQL in migrations using &lt;a href=&quot;https://docs.djangoproject.com/en/2.1/ref/migration-operations/#runsql&quot;&gt;&lt;code&gt;RunSQL&lt;/code&gt;&lt;/a&gt;. Let&amp;rsquo;s try to use it instead of executing the command directly in the database.&lt;/p&gt;
&lt;p&gt;First, generate a new empty migration:&lt;/p&gt;
&lt;div class=&quot;highlight sh&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; python manage.py makemigrations app --empty --name add_index_runsql
&lt;span class=&quot;go&quot;&gt;Migrations for &amp;#39;app&amp;#39;:&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  app/migrations/0002_add_index_runsql.py&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Next, edit the migration file and add a &lt;code&gt;RunSQL&lt;/code&gt; operation:&lt;/p&gt;
&lt;div class=&quot;highlight python&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;# migrations/0002_add_index_runsql.py&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;django.db&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;migrations&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;models&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Migration&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;migrations&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Migration&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;atomic&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;False&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;dependencies&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;app&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;0001_initial&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;operations&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;migrations&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;RunSQL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
&lt;span class=&quot;hll&quot;&gt;            &lt;span class=&quot;s1&quot;&gt;&amp;#39;CREATE INDEX &amp;quot;app_sale_sold_at_b9438ae4&amp;quot; &amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;hll&quot;&gt;            &lt;span class=&quot;s1&quot;&gt;&amp;#39;ON &amp;quot;app_sale&amp;quot; (&amp;quot;sold_at&amp;quot;);&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;hll&quot;&gt;        &lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;hll&quot;&gt;    &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;When you run the migration, you will get the following output:&lt;/p&gt;
&lt;div class=&quot;highlight sh&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; python manage.py migrate
&lt;span class=&quot;go&quot;&gt;Operations to perform:&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  Apply all migrations: app&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Running migrations:&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  Applying app.0002_add_index_runsql... OK&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This is looking good, but there is a problem. Let&amp;rsquo;s try to generate migrations again:&lt;/p&gt;
&lt;div class=&quot;highlight sh&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; python manage.py makemigrations --name leftover_migration
&lt;span class=&quot;go&quot;&gt;Migrations for &amp;#39;app&amp;#39;:&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  app/migrations/0003_leftover_migration.py&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;    - Alter field sold_at on sale&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Django generated the same migration again. Why did it do that?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Cleanup&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Before we can answer that question, you need to clean up and undo the changes you made to the database. Start by deleting the last migration. It was not applied, so it&amp;rsquo;s safe to delete:&lt;/p&gt;
&lt;div class=&quot;highlight sh&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; rm app/migrations/0003_leftover_migration.py
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Next, list the migrations for the &lt;code&gt;app&lt;/code&gt; app:&lt;/p&gt;
&lt;div class=&quot;highlight sh&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; python manage.py showmigrations app
&lt;span class=&quot;go&quot;&gt;app&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt; [X] 0001_initial&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt; [X] 0002_add_index_runsql&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The third migration is gone, but the second is applied. You want to get back to the state right after the initial migration. Try to migrate back to the initial migration as you did in the previous section:&lt;/p&gt;
&lt;div class=&quot;highlight sh&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; python manage.py migrate app &lt;span class=&quot;m&quot;&gt;0001&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Operations to perform:&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  Target specific migration: 0001_initial, from app&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Running migrations:&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  Rendering model states... DONE&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  Unapplying app.0002_add_index_runsql...Traceback (most recent call last):&lt;/span&gt;

&lt;span class=&quot;go&quot;&gt;NotImplementedError: You cannot reverse this operation&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Django is unable to reverse the migration.&lt;/p&gt;
&lt;h2 id=&quot;reverse-migration-operation&quot;&gt;Reverse Migration Operation&lt;/h2&gt;
&lt;p&gt;To reverse a migration, Django executes an opposite action for every operation. In this case, the reverse of adding an index is to drop it. As you&amp;rsquo;ve already seen, when a migration is reversible, you can unapply it. Just like you can use &lt;code&gt;checkout&lt;/code&gt; in Git, you can reverse a migration if you execute &lt;code&gt;migrate&lt;/code&gt; to an earlier migration.&lt;/p&gt;
&lt;p&gt;Many built-in migration operations already define a reverse action. For example, the reverse action for adding a field is to drop the corresponding column. The reverse action for creating a model is to drop the corresponding table.&lt;/p&gt;
&lt;p&gt;Some migration operations are not reversible. For example, there is no reverse action for removing a field or deleting a model, because once the migration was applied, the data is gone.&lt;/p&gt;
&lt;p&gt;In the previous section, you used the &lt;code&gt;RunSQL&lt;/code&gt; operation. When you tried to reverse the migration, you encountered an error. According to the error, one of the operations in the migration cannot be reversed. Django is unable to reverse raw SQL by default. Because Django has no knowledge of what was executed by the operation, it cannot generate an opposite action automatically.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;How to Make a Migration Reversible&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;For a migration to be reversible, all the operations in it must be reversible. It&amp;rsquo;s not possible to reverse part of a migration, so a single non-reversible operation will make the entire migration non-reversible.&lt;/p&gt;
&lt;p&gt;To make a &lt;code&gt;RunSQL&lt;/code&gt; operation reversible, you must provide SQL to execute when the operation is reversed. The reverse SQL is provided in the &lt;code&gt;reverse_sql&lt;/code&gt; argument.&lt;/p&gt;
&lt;p&gt;The opposite action to adding an index is to drop it. To make your migration reversible, provide the &lt;code&gt;reverse_sql&lt;/code&gt; to drop the index:&lt;/p&gt;
&lt;div class=&quot;highlight python&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;# migrations/0002_add_index_runsql.py&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;django.db&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;migrations&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;models&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Migration&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;migrations&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Migration&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;atomic&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;False&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;dependencies&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;app&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;0001_initial&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;operations&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;migrations&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;RunSQL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
            &lt;span class=&quot;s1&quot;&gt;&amp;#39;CREATE INDEX &amp;quot;app_sale_sold_at_b9438ae4&amp;quot; &amp;#39;&lt;/span&gt;
            &lt;span class=&quot;s1&quot;&gt;&amp;#39;ON &amp;quot;app_sale&amp;quot; (&amp;quot;sold_at&amp;quot;);&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;

            &lt;span class=&quot;n&quot;&gt;reverse_sql&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;DROP INDEX &amp;quot;app_sale_sold_at_b9438ae4&amp;quot;;&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;hll&quot;&gt;        &lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
&lt;/span&gt;    &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now try to reverse the migration:&lt;/p&gt;
&lt;div class=&quot;highlight sh&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; python manage.py showmigrations app
&lt;span class=&quot;go&quot;&gt;app&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt; [X] 0001_initial&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt; [X] 0002_add_index_runsql&lt;/span&gt;

&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; python manage.py migrate app &lt;span class=&quot;m&quot;&gt;0001&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Operations to perform:&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  Target specific migration: 0001_initial, from app&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Running migrations:&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  Rendering model states... DONE&lt;/span&gt;
&lt;span class=&quot;hll&quot;&gt;&lt;span class=&quot;go&quot;&gt; Unapplying app.0002_add_index_runsql... OK&lt;/span&gt;
&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; python manage.py showmigrations app
&lt;span class=&quot;go&quot;&gt;app&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt; [X] 0001_initial&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt; [ ] 0002_add_index_runsql&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The second migration was reversed, and the index was dropped by Django. Now it&amp;rsquo;s safe to delete the migration file:&lt;/p&gt;
&lt;div class=&quot;highlight sh&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; rm app/migrations/0002_add_index_runsql.py
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;It&amp;rsquo;s always a good idea to provide &lt;code&gt;reverse_sql&lt;/code&gt;. In situations where reversing a raw SQL operation does not require any action, you can mark the operation as reversible using the special sentinel &lt;code&gt;migrations.RunSQL.noop&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight python&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;migrations&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;RunSQL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;sql&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;...&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# Your forward SQL here&lt;/span&gt;
&lt;span class=&quot;hll&quot;&gt;    &lt;span class=&quot;n&quot;&gt;reverse_sql&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;migrations&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;RunSQL&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;noop&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id=&quot;understand-model-state-and-database-state&quot;&gt;Understand Model State and Database State&lt;/h2&gt;
&lt;p&gt;In your previous attempt to create the index manually using &lt;code&gt;RunSQL&lt;/code&gt;, Django generated the same migration over and over again even though the index was created in the database. To understand why Django did that, you first need to understand how Django decides when to generate new migrations.&lt;/p&gt;
&lt;h3 id=&quot;when-django-generates-a-new-migration&quot;&gt;When Django Generates a New Migration&lt;/h3&gt;
&lt;p&gt;In the process of generating and applying migrations, Django syncs between the state of the database and the state of the models. For example, when you add a field to a model, Django adds a column to the table. When you remove a field from the model, Django removes the column from the table.&lt;/p&gt;
&lt;p&gt;To sync between the models and the database, Django maintains a state that represents the models. To sync the database with the models, Django generates migration operations. Migration operations translate to a vendor specific SQL that can be executed in the database. When all migration operations are executed, the database and the models are expected to be consistent.&lt;/p&gt;
&lt;p&gt;To get the state of the database, Django aggregates the operations from all past migrations. When the aggregated state of the migrations is not consistent with the state of the models, Django generates a new migration.&lt;/p&gt;
&lt;p&gt;In the previous example, you created the index using raw SQL. Django did not know you created the index because you didn&amp;rsquo;t use a familiar migration operation.&lt;/p&gt;
&lt;p&gt;When Django aggregated all the migrations and compared them with the state of the models, it found that an index was missing. This is why, even after you created the index manually, Django still thought it was missing and generated a new migration for it.&lt;/p&gt;
&lt;h3 id=&quot;how-to-separate-database-and-state-in-migrations&quot;&gt;How to Separate Database and State in Migrations&lt;/h3&gt;
&lt;p&gt;Since Django is unable to create the index the way you want it to, you want to provide your own SQL but still let Django know you created it.&lt;/p&gt;
&lt;p&gt;In other words, you need to execute something in the database and provide Django with the migration operation to sync its internal state. To do that, Django provides us with a special migration operation called &lt;a href=&quot;https://docs.djangoproject.com/en/2.1/ref/migration-operations/#separatedatabaseandstate&quot;&gt;&lt;code&gt;SeparateDatabaseAndState&lt;/code&gt;&lt;/a&gt;. This operation is not well known and should be reserved for special cases such as this one.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s much easier to edit migrations than write them from scratch, so start by generating a migration the usual way:&lt;/p&gt;
&lt;div class=&quot;highlight sh&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; python manage.py makemigrations --name add_index_separate_database_and_state

&lt;span class=&quot;go&quot;&gt;Migrations for &amp;#39;app&amp;#39;:&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  app/migrations/0002_add_index_separate_database_and_state.py&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;    - Alter field sold_at on sale&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This is the contents of the migration generated by Django, same as before:&lt;/p&gt;
&lt;div class=&quot;highlight python&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;# migrations/0002_add_index_separate_database_and_state.py&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;django.db&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;migrations&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;models&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Migration&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;migrations&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Migration&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;dependencies&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;app&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;0001_initial&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;operations&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;migrations&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;AlterField&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;model_name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;sale&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;sold_at&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;models&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;DateTimeField&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;auto_now_add&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;db_index&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Django generated an &lt;code&gt;AlterField&lt;/code&gt; operation on the field &lt;code&gt;sold_at&lt;/code&gt;. The operation will create an index and update the state. We want to keep this operation but provide a different command to execute in the database.&lt;/p&gt;
&lt;p&gt;Once again, to get the command, use the SQL generated by Django:&lt;/p&gt;
&lt;div class=&quot;highlight sh&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; python manage.py sqlmigrate app &lt;span class=&quot;m&quot;&gt;0002&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;BEGIN;&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;--&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;-- Alter field sold_at on sale&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;--&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;CREATE INDEX &amp;quot;app_sale_sold_at_b9438ae4&amp;quot; ON &amp;quot;app_sale&amp;quot; (&amp;quot;sold_at&amp;quot;);&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;COMMIT;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Add the &lt;code&gt;CONCURRENTLY&lt;/code&gt; keyword in the appropriate place:&lt;/p&gt;
&lt;div class=&quot;highlight sql&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;INDEX&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CONCURRENTLY&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;&amp;quot;app_sale_sold_at_b9438ae4&amp;quot;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;ON&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;&amp;quot;app_sale&amp;quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;&amp;quot;sold_at&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Next, edit the migration file and use &lt;code&gt;SeparateDatabaseAndState&lt;/code&gt; to provide your modified SQL command for execution:&lt;/p&gt;
&lt;div class=&quot;highlight python&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;# migrations/0002_add_index_separate_database_and_state.py&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;django.db&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;migrations&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;models&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Migration&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;migrations&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Migration&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;dependencies&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;app&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;0001_initial&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;operations&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;

        &lt;span class=&quot;n&quot;&gt;migrations&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SeparateDatabaseAndState&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;

            &lt;span class=&quot;n&quot;&gt;state_operations&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;migrations&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;AlterField&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
                    &lt;span class=&quot;n&quot;&gt;model_name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;sale&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                    &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;sold_at&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                    &lt;span class=&quot;n&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;models&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;DateTimeField&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
                        &lt;span class=&quot;n&quot;&gt;auto_now_add&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                        &lt;span class=&quot;n&quot;&gt;db_index&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                    &lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
                &lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;

            &lt;span class=&quot;n&quot;&gt;database_operations&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;migrations&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;RunSQL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sql&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;span class=&quot;s2&quot;&gt;                    CREATE INDEX CONCURRENTLY &amp;quot;app_sale_sold_at_b9438ae4&amp;quot;&lt;/span&gt;
&lt;span class=&quot;s2&quot;&gt;                    ON &amp;quot;app_sale&amp;quot; (&amp;quot;sold_at&amp;quot;);&lt;/span&gt;
&lt;span class=&quot;s2&quot;&gt;                &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;reverse_sql&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;span class=&quot;s2&quot;&gt;                    DROP INDEX &amp;quot;app_sale_sold_at_b9438ae4&amp;quot;;&lt;/span&gt;
&lt;span class=&quot;s2&quot;&gt;                &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;

    &lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The migration operation &lt;code&gt;SeparateDatabaseAndState&lt;/code&gt; accepts 2 lists of operations:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;state_operations&lt;/strong&gt; are operations to apply on the internal model state. They do not effect the database.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;database_operations&lt;/strong&gt; are operations to apply to the database.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;You kept the original operation generated by Django in &lt;code&gt;state_operations&lt;/code&gt;. When using &lt;code&gt;SeparateDatabaseAndState&lt;/code&gt;, this is what you will usually want to do. Notice that the &lt;code&gt;db_index=True&lt;/code&gt; argument is provided to the field. This migration operation will let Django know that there is an index on the field.&lt;/p&gt;
&lt;p&gt;You used the SQL generated by Django and added the &lt;code&gt;CONCURRENTLY&lt;/code&gt; keyword. You used the special action &lt;a href=&quot;https://docs.djangoproject.com/en/2.1/ref/migration-operations/#runsql&quot;&gt;&lt;code&gt;RunSQL&lt;/code&gt;&lt;/a&gt; to execute raw SQL in the migration.&lt;/p&gt;
&lt;p&gt;If you try to run the migration, you will get the following output:&lt;/p&gt;
&lt;div class=&quot;highlight sh&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; python manage.py migrate app
&lt;span class=&quot;go&quot;&gt;Operations to perform:&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  Apply all migrations: app&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Running migrations:&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  Applying app.0002_add_index_separate_database_and_state...Traceback (most recent call last):&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  File &amp;quot;/venv/lib/python3.7/site-packages/django/db/backends/utils.py&amp;quot;, line 83, in _execute&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;    return self.cursor.execute(sql)&lt;/span&gt;
&lt;span class=&quot;hll&quot;&gt;&lt;span class=&quot;go&quot;&gt;psycopg2.InternalError: CREATE INDEX CONCURRENTLY cannot run inside a transaction block&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id=&quot;non-atomic-migrations&quot;&gt;Non-Atomic Migrations&lt;/h2&gt;
&lt;p&gt;In SQL, &lt;code&gt;CREATE&lt;/code&gt;, &lt;code&gt;DROP&lt;/code&gt;, &lt;code&gt;ALTER&lt;/code&gt;, and &lt;code&gt;TRUNCATE&lt;/code&gt; operations are referred to as &lt;strong&gt;Data Definition Language&lt;/strong&gt; (DDL). In databases that support transactional DDL, &lt;a href=&quot;https://wiki.postgresql.org/wiki/Transactional_DDL_in_PostgreSQL:_A_Competitive_Analysis#Transactional_DDL&quot;&gt;such as PostgreSQL&lt;/a&gt;, Django executes migrations inside a database transaction by default. However, according to the error above, PostgreSQL cannot create an index concurrently inside a transaction block.&lt;/p&gt;
&lt;p&gt;To be able to create an index concurrently within a migration, you need to tell Django to not execute the migration in a database transaction. To do that, you mark the migration as &lt;a href=&quot;https://docs.djangoproject.com/en/2.1/howto/writing-migrations/#non-atomic-migrations&quot;&gt;non-atomic&lt;/a&gt; by setting &lt;code&gt;atomic&lt;/code&gt; to &lt;code&gt;False&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight python&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;# migrations/0002_add_index_separate_database_and_state.py&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;django.db&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;migrations&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;models&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Migration&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;migrations&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Migration&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
&lt;span class=&quot;hll&quot;&gt;    &lt;span class=&quot;n&quot;&gt;atomic&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;False&lt;/span&gt;
&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;dependencies&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;app&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;0001_initial&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;operations&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;

        &lt;span class=&quot;n&quot;&gt;migrations&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SeparateDatabaseAndState&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;

            &lt;span class=&quot;n&quot;&gt;state_operations&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;migrations&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;AlterField&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
                    &lt;span class=&quot;n&quot;&gt;model_name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;sale&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                    &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;sold_at&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                    &lt;span class=&quot;n&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;models&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;DateTimeField&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
                        &lt;span class=&quot;n&quot;&gt;auto_now_add&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                        &lt;span class=&quot;n&quot;&gt;db_index&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                    &lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
                &lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;

            &lt;span class=&quot;n&quot;&gt;database_operations&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;migrations&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;RunSQL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sql&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;span class=&quot;s2&quot;&gt;                    CREATE INDEX CONCURRENTLY &amp;quot;app_sale_sold_at_b9438ae4&amp;quot;&lt;/span&gt;
&lt;span class=&quot;s2&quot;&gt;                    ON &amp;quot;app_sale&amp;quot; (&amp;quot;sold_at&amp;quot;);&lt;/span&gt;
&lt;span class=&quot;s2&quot;&gt;                &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;reverse_sql&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;span class=&quot;s2&quot;&gt;                    DROP INDEX &amp;quot;app_sale_sold_at_b9438ae4&amp;quot;;&lt;/span&gt;
&lt;span class=&quot;s2&quot;&gt;                &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;

    &lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;After you marked the migration as non-atomic, you can run the migration:&lt;/p&gt;
&lt;div class=&quot;highlight sh&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; python manage.py migrate app
&lt;span class=&quot;go&quot;&gt;Operations to perform:&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  Apply all migrations: app&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Running migrations:&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  Applying app.0002_add_index_separate_database_and_state... OK&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You just executed the migration without causing any downtime.&lt;/p&gt;
&lt;p&gt;Here are some issues to consider when you&amp;rsquo;re using &lt;code&gt;SeparateDatabaseAndState&lt;/code&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Database operations must be equivalent to state operations:&lt;/strong&gt; Inconsistencies between the database and model state can cause a lot of trouble. A good starting point is to keep the operations generated by Django in &lt;code&gt;state_operations&lt;/code&gt; and edit the output of &lt;code&gt;sqlmigrate&lt;/code&gt; to use in &lt;code&gt;database_operations&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Non atomic migrations cannot rollback in case of error:&lt;/strong&gt; If there is an error during the migration, then you won&amp;rsquo;t be able to rollback. You would have to either rollback the migration or complete it manually. It&amp;rsquo;s a good idea to keep the operations executed inside a non-atomic migration to a minimum. If you have additional operations in the migration, move them to a new migration.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Migration might be vendor specific:&lt;/strong&gt; The SQL generated by Django is specific to the database backend used in the project. It might work with other database backends, but that is not guaranteed. If you need to support multiple database backends, you need to make some adjustments to this approach.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;You started this tutorial with a large table and a problem. You wanted to make your app faster for your users, and you wanted to do that without causing them any downtime.&lt;/p&gt;
&lt;p&gt;By the end of the tutorial, you managed to generate and safely modify a Django migration to achieve this goal. You tackled different problems along the way and managed to overcome them using built-in tools provided by the migrations framework.&lt;/p&gt;
&lt;p&gt;In this tutorial, you learned the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;How Django migrations work internally using model and database state, and when new migrations are generated&lt;/li&gt;
&lt;li&gt;How to execute custom SQL in migrations using the &lt;code&gt;RunSQL&lt;/code&gt; action&lt;/li&gt;
&lt;li&gt;What reversible migrations are, and how to make a &lt;code&gt;RunSQL&lt;/code&gt; action reversible&lt;/li&gt;
&lt;li&gt;What atomic migrations are, and how to change the default behavior according to your needs&lt;/li&gt;
&lt;li&gt;How to safely execute complex migrations in Django&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The separation between model and database state is an important concept. Once you understand it, and how to utilize it, you can overcome many limitations of the built-in migration operations. Some use cases that come to mind include adding an index that was already created in the database and providing vendor specific arguments to DDL commands.&lt;/p&gt;
        &lt;hr /&gt;
        &lt;p&gt;&lt;em&gt;[ Improve Your Python With 🐍 Python Tricks 💌 – Get a short &amp;amp; sweet Python Trick delivered to your inbox every couple of days. &lt;a href=&quot;https://realpython.com/python-tricks/?utm_source=realpython&amp;amp;utm_medium=rss&amp;amp;utm_campaign=footer&quot;&gt;&amp;gt;&amp;gt; Click here to learn more and see examples&lt;/a&gt; ]&lt;/em&gt;&lt;/p&gt;
      </content>
    </entry>
  
    <entry>
      <title>Running Python Scripts</title>
      <id>https://realpython.com/courses/running-python-scripts/</id>
      <link href="https://realpython.com/courses/running-python-scripts/"/>
      <updated>2019-04-09T14:00:00+00:00</updated>
      <summary>This step-by-step course will guide you through a series of ways to run Python scripts, depending on your environment, platform, needs, and skills as a programmer.</summary>
      <content type="html">
        &lt;p&gt;One of the most important skills you need to build as a Python developer is to be able to run Python scripts and code. This is going to be the only way for you to know if your code works as you planned. It&amp;rsquo;s even the only way of knowing if your code works at all!&lt;/p&gt;
&lt;p&gt;This step-by-step course will guide you through a series of ways to run Python scripts, depending on your environment, platform, needs, and skills as a programmer.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;You&amp;rsquo;ll learn how to run Python scripts by using:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The operating system command-line or terminal&lt;/li&gt;
&lt;li&gt;The Python interactive mode&lt;/li&gt;
&lt;li&gt;The IDE or text editor you like best&lt;/li&gt;
&lt;li&gt;The file manager of your system, by double-clicking on the icon of your script&lt;/li&gt;
&lt;/ul&gt;
        &lt;hr /&gt;
        &lt;p&gt;&lt;em&gt;[ Improve Your Python With 🐍 Python Tricks 💌 – Get a short &amp;amp; sweet Python Trick delivered to your inbox every couple of days. &lt;a href=&quot;https://realpython.com/python-tricks/?utm_source=realpython&amp;amp;utm_medium=rss&amp;amp;utm_campaign=footer&quot;&gt;&amp;gt;&amp;gt; Click here to learn more and see examples&lt;/a&gt; ]&lt;/em&gt;&lt;/p&gt;
      </content>
    </entry>
  
    <entry>
      <title>Python REST APIs With Flask, Connexion, and SQLAlchemy – Part 3</title>
      <id>https://realpython.com/flask-connexion-rest-api-part-3/</id>
      <link href="https://realpython.com/flask-connexion-rest-api-part-3/"/>
      <updated>2019-04-08T14:00:00+00:00</updated>
      <summary>In Part 3 of this series, you&#39;ll learn how to add relationships to the database created in Part 2 and extend the API to support CRUD operations on those relationships using SQLAlchemy and Marshmallow.</summary>
      <content type="html">
        &lt;p&gt;In &lt;a href=&quot;https://realpython.com/flask-connexion-rest-api-part-2/&quot;&gt;Part 2&lt;/a&gt; of this series, you added the ability to save changes made through the REST API to a database using &lt;a href=&quot;https://www.sqlalchemy.org/&quot;&gt;SQLAlchemy&lt;/a&gt; and learned how to &lt;a href=&quot;https://en.wikipedia.org/wiki/Serialization&quot;&gt;serialize&lt;/a&gt; that data for the REST API using &lt;a href=&quot;https://marshmallow.readthedocs.io/en/3.0/&quot;&gt;Marshmallow&lt;/a&gt;. Connecting the REST API to a database so that the application can make changes to existing data and create new data is great and makes the application much more useful and robust. &lt;/p&gt;
&lt;p&gt;That&amp;rsquo;s only part of the power a database offers, however. An even more powerful feature is the &lt;strong&gt;R&lt;/strong&gt; part of &lt;strong&gt;RDBMS&lt;/strong&gt; systems: &lt;strong&gt;relationships&lt;/strong&gt;. In a database, a relationship is the ability to connect two or more tables together in a meaningful way. In this article, you&amp;rsquo;ll learn how to implement relationships and turn your &lt;code&gt;Person&lt;/code&gt; database into a mini-blogging web application.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;In this article, you&amp;rsquo;ll learn:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Why more than one table in a database is useful and important&lt;/li&gt;
&lt;li&gt;How tables are related to each other&lt;/li&gt;
&lt;li&gt;How SQLAlchemy can help you manage relationships&lt;/li&gt;
&lt;li&gt;How relationships help you build a mini-blogging application&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;who-this-article-is-for&quot;&gt;Who This Article Is For&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://realpython.com/flask-connexion-rest-api/&quot;&gt;Part 1&lt;/a&gt; of this series guided you through building a REST API, and &lt;a href=&quot;https://realpython.com/flask-connexion-rest-api-part-2/&quot;&gt;Part 2&lt;/a&gt; showed you how to connect that REST API to a database. &lt;/p&gt;
&lt;p&gt;This article expands your programming tool belt further. You&amp;rsquo;ll learn how to create hierarchical data structures represented as &lt;a href=&quot;https://en.wikipedia.org/wiki/One-to-many_(data_model)&quot;&gt;one-to-many&lt;/a&gt; relationships by SQLAlchemy. In addition, you&amp;rsquo;ll extend the REST API you&amp;rsquo;ve already built to provide CRUD (Create, Read, Update, and Delete) support for the elements in this hierarchical structure. &lt;/p&gt;
&lt;p&gt;The web application presented in Part 2 will have its HTML and JavaScript files modified in major ways to create a more fully functional mini-blogging application. You can review the final version of the code from Part 2 in the &lt;a href=&quot;https://github.com/realpython/materials/tree/master/flask-connexion-rest-part-2/version_1&quot;&gt;GitHub repository for that article&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Hang on as you get started creating relationships and your mini-blogging application!&lt;/p&gt;
&lt;h2 id=&quot;additional-dependencies&quot;&gt;Additional Dependencies&lt;/h2&gt;
&lt;p&gt;There are no new Python dependencies beyond what was required for the Part 2 article. However, you will be using two new JavaScript modules in the web application to makes things easier and more consistent. The two modules are the following:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://handlebarsjs.com/&quot;&gt;Handlebars.js&lt;/a&gt;&lt;/strong&gt; is a templating engine for JavaScript, much like &lt;a href=&quot;https://realpython.com/primer-on-jinja-templating/&quot;&gt;Jinja2&lt;/a&gt; for Flask.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://momentjs.com/&quot;&gt;Moment.js&lt;/a&gt;&lt;/strong&gt; is a datetime parsing and formatting module that makes displaying UTC timestamps easier. &lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;You don&amp;rsquo;t have to download either of these, as the web application will get them directly from the &lt;a href=&quot;https://www.cloudflare.com/&quot;&gt;Cloudflare CDN&lt;/a&gt; (&lt;a href=&quot;https://en.wikipedia.org/wiki/Content_delivery_network&quot;&gt;Content Delivery Network&lt;/a&gt;), as you&amp;rsquo;re already doing for the jQuery module. &lt;/p&gt;
&lt;h2 id=&quot;people-data-extended-for-blogging&quot;&gt;People Data Extended for Blogging&lt;/h2&gt;
&lt;p&gt;In Part 2, the &lt;code&gt;People&lt;/code&gt; data existed as a dictionary in the &lt;code&gt;build_database.py&lt;/code&gt; Python code. This is what you used to populate the database with some initial data. You&amp;rsquo;re going to modify the &lt;code&gt;People&lt;/code&gt; data structure to give each person a list of notes associated with them. The new &lt;code&gt;People&lt;/code&gt; data structure will look like this:&lt;/p&gt;
&lt;div class=&quot;highlight python&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;# Data to initialize database with&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;PEOPLE&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;s2&quot;&gt;&amp;quot;fname&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;Doug&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s2&quot;&gt;&amp;quot;lname&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;Farrell&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s2&quot;&gt;&amp;quot;notes&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;Cool, a mini-blogging application!&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;2019-01-06 22:17:54&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;This could be useful&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;2019-01-08 22:17:54&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;Well, sort of useful&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;2019-03-06 22:17:54&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;s2&quot;&gt;&amp;quot;fname&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;Kent&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s2&quot;&gt;&amp;quot;lname&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;Brockman&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s2&quot;&gt;&amp;quot;notes&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
                &lt;span class=&quot;s2&quot;&gt;&amp;quot;I&amp;#39;m going to make really profound observations&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                &lt;span class=&quot;s2&quot;&gt;&amp;quot;2019-01-07 22:17:54&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
                &lt;span class=&quot;s2&quot;&gt;&amp;quot;Maybe they&amp;#39;ll be more obvious than I thought&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                &lt;span class=&quot;s2&quot;&gt;&amp;quot;2019-02-06 22:17:54&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;s2&quot;&gt;&amp;quot;fname&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;Bunny&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s2&quot;&gt;&amp;quot;lname&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;Easter&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s2&quot;&gt;&amp;quot;notes&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;Has anyone seen my Easter eggs?&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;2019-01-07 22:47:54&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;I&amp;#39;m really late delivering these!&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;2019-04-06 22:17:54&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Each person in the &lt;code&gt;People&lt;/code&gt; dictionary now includes a key called &lt;code&gt;notes&lt;/code&gt;, which is associated with a list containing tuples of data. Each tuple in the &lt;code&gt;notes&lt;/code&gt; list represents a single &lt;strong&gt;note&lt;/strong&gt; containing the content and a timestamp. The timestamps are initialized (rather than dynamically created) to demonstrate ordering later on in the REST API.&lt;/p&gt;
&lt;p&gt;Each single person is associated with multiple notes, and each single note is associated with only one person. This hierarchy of data is known as a &lt;a href=&quot;https://en.wikipedia.org/wiki/One-to-many_(data_model)&quot;&gt;one-to-many&lt;/a&gt; relationship, where a single parent object is related to many child objects. You&amp;rsquo;ll see how this one-to-many relationship is managed in the database with SQLAlchemy.&lt;/p&gt;
&lt;h2 id=&quot;brute-force-approach&quot;&gt;Brute Force Approach&lt;/h2&gt;
&lt;p&gt;The database you built stored the data in a table, and a table is a two-dimensional array of rows and columns. Can the &lt;code&gt;People&lt;/code&gt; dictionary above be represented in a single table of rows and columns? It can be, in the following way, in your &lt;code&gt;person&lt;/code&gt; database table. Unfortunately to include all of the actual data in the example creates a scroll bar for the table, as you&amp;rsquo;ll see below:&lt;/p&gt;
&lt;div class=&quot;table-responsive&quot;&gt;
&lt;table class=&quot;table table-hover&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;code&gt;person_id&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;&lt;code&gt;lname&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;&lt;code&gt;fname&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;&lt;code&gt;timestamp&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;&lt;code&gt;content&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;&lt;code&gt;note_timestamp&lt;/code&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Farrell&lt;/td&gt;
&lt;td&gt;Doug&lt;/td&gt;
&lt;td&gt;2018-08-08 21:16:01&lt;/td&gt;
&lt;td&gt;Cool, a mini-blogging application!&lt;/td&gt;
&lt;td&gt;2019-01-06 22:17:54&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Farrell&lt;/td&gt;
&lt;td&gt;Doug&lt;/td&gt;
&lt;td&gt;2018-08-08 21:16:01&lt;/td&gt;
&lt;td&gt;This could be useful&lt;/td&gt;
&lt;td&gt;2019-01-08 22:17:54&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;Farrell&lt;/td&gt;
&lt;td&gt;Doug&lt;/td&gt;
&lt;td&gt;2018-08-08 21:16:01&lt;/td&gt;
&lt;td&gt;Well, sort of useful&lt;/td&gt;
&lt;td&gt;2019-03-06 22:17:54&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;Brockman&lt;/td&gt;
&lt;td&gt;Kent&lt;/td&gt;
&lt;td&gt;2018-08-08 21:16:01&lt;/td&gt;
&lt;td&gt;I&amp;rsquo;m going to make really profound observations&lt;/td&gt;
&lt;td&gt;2019-01-07 22:17:54&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;Brockman&lt;/td&gt;
&lt;td&gt;Kent&lt;/td&gt;
&lt;td&gt;2018-08-08 21:16:01&lt;/td&gt;
&lt;td&gt;Maybe they&amp;rsquo;ll be more obvious than I thought&lt;/td&gt;
&lt;td&gt;2019-02-06 22:17:54&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;Easter&lt;/td&gt;
&lt;td&gt;Bunny&lt;/td&gt;
&lt;td&gt;2018-08-08 21:16:01&lt;/td&gt;
&lt;td&gt;Has anyone seen my Easter eggs?&lt;/td&gt;
&lt;td&gt;2019-01-07 22:47:54&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;Easter&lt;/td&gt;
&lt;td&gt;Bunny&lt;/td&gt;
&lt;td&gt;2018-08-08 21:16:01&lt;/td&gt;
&lt;td&gt;I&amp;rsquo;m really late delivering these!&lt;/td&gt;
&lt;td&gt;2019-04-06 22:17:54&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;p&gt;The above table would actually work. All the data is represented, and a single person is associated with a collection of different notes. &lt;/p&gt;
&lt;h3 id=&quot;advantages&quot;&gt;Advantages&lt;/h3&gt;
&lt;p&gt;Conceptually, the above table structure has the advantage of being relatively simple to understand. You could even make the case that the data could be persisted to a flat file instead of a database.&lt;/p&gt;
&lt;p&gt;Because of the two-dimensional table structure, you could store and use this data in a spreadsheet. Spreadsheets have been pressed into service as data storage quite a bit.&lt;/p&gt;
&lt;h3 id=&quot;disadvantages&quot;&gt;Disadvantages&lt;/h3&gt;
&lt;p&gt;While the above table structure would work, it has some real disadvantages. &lt;/p&gt;
&lt;p&gt;In order to represent the collection of notes, all the data for each person is repeated for every unique note, the person data is therefore redundant. This isn&amp;rsquo;t such a big deal for your person data as there aren&amp;rsquo;t that many columns. But imagine if a person had many more columns. Even with large disk drives, this can get to be a storage concern if you&amp;rsquo;re dealing with millions of rows of data.&lt;/p&gt;
&lt;p&gt;Having redundant data like this can lead to maintenance issues as time goes by. For example, what if the Easter Bunny decided a change of name was a good idea. In order to do this, every record containing the Easter Bunny&amp;rsquo;s name would have to be updated in order to keep the data consistent. This kind of work against the database can lead to data inconsistency, particularly if the work is done by a person running a SQL query by hand. &lt;/p&gt;
&lt;p&gt;Naming columns becomes awkward. In the table above, there is a &lt;code&gt;timestamp&lt;/code&gt; column used to track the creation and update time of a person in the table. You also want to have similar functionality for the creation and update time for a note, but because &lt;code&gt;timestamp&lt;/code&gt; is already used, a contrived name of &lt;code&gt;note_timestamp&lt;/code&gt; is used.&lt;/p&gt;
&lt;p&gt;What if you wanted to add additional one-to-many relationships to the &lt;code&gt;person&lt;/code&gt; table? For example, to include a person&amp;rsquo;s children or phone numbers. Each person could have multiple children and multiple phone numbers. This could be done relatively easily to the Python &lt;code&gt;People&lt;/code&gt; dictionary above by adding &lt;code&gt;children&lt;/code&gt; and &lt;code&gt;phone_numbers&lt;/code&gt; keys with new lists containing the data. &lt;/p&gt;
&lt;p&gt;However, representing those new one-to-many relationships in your &lt;code&gt;person&lt;/code&gt; database table above becomes significantly more difficult. Every new one-to-many relationship increases the number of rows necessary to represent it for every single entry in the child data dramatically. In addition, the problems associated with data redundancy get bigger and more difficult to handle.&lt;/p&gt;
&lt;p&gt;Lastly, the data you&amp;rsquo;d get back from the above table structure wouldn&amp;rsquo;t be very Pythonic: it would be just a big list of lists. SQLAlchemy wouldn&amp;rsquo;t be able to help you very much because the relationship isn&amp;rsquo;t there.&lt;/p&gt;
&lt;h2 id=&quot;relational-database-approach&quot;&gt;Relational Database Approach&lt;/h2&gt;
&lt;p&gt;Based on what you&amp;rsquo;ve seen above, it becomes clear that trying to represent even a moderately complex dataset in a single table becomes unmanageable pretty quickly. Given that, what alternative does a database offer? This is where the &lt;strong&gt;R&lt;/strong&gt; part of &lt;strong&gt;RDBMS&lt;/strong&gt; databases comes into play. Representing relationships removes the disadvantages outlined above. &lt;/p&gt;
&lt;p&gt;Instead of trying to represent hierarchical data in a single table, the data is broken up into multiple tables, with a mechanism to relate them to one another. The tables are broken along collection lines, so for your &lt;code&gt;People&lt;/code&gt; dictionary above, this means there will be a table representing people and another representing notes. This brings back your original &lt;code&gt;person&lt;/code&gt; table, which looks like this:&lt;/p&gt;
&lt;div class=&quot;table-responsive&quot;&gt;
&lt;table class=&quot;table table-hover&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;code&gt;person_id&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;&lt;code&gt;lname&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;&lt;code&gt;fname&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;&lt;code&gt;timestamp&lt;/code&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Farrell&lt;/td&gt;
&lt;td&gt;Doug&lt;/td&gt;
&lt;td&gt;2018-08-08 21:16:01.888444&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Brockman&lt;/td&gt;
&lt;td&gt;Kent&lt;/td&gt;
&lt;td&gt;2018-08-08 21:16:01.889060&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;Easter&lt;/td&gt;
&lt;td&gt;Bunny&lt;/td&gt;
&lt;td&gt;2018-08-08 21:16:01.886834&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;p&gt;To represent the new note information, you&amp;rsquo;ll create a new table called &lt;code&gt;note&lt;/code&gt;. (Remember our singular table naming convention.) The table looks like this:&lt;/p&gt;
&lt;div class=&quot;table-responsive&quot;&gt;
&lt;table class=&quot;table table-hover&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;code&gt;note_id&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;&lt;code&gt;person_id&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;&lt;code&gt;content&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;&lt;code&gt;timestamp&lt;/code&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Cool, a mini-blogging application!&lt;/td&gt;
&lt;td&gt;2019-01-06 22:17:54&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;This could be useful&lt;/td&gt;
&lt;td&gt;2019-01-08 22:17:54&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Well, sort of useful&lt;/td&gt;
&lt;td&gt;2019-03-06 22:17:54&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;I&amp;rsquo;m going to make really profound observations&lt;/td&gt;
&lt;td&gt;2019-01-07 22:17:54&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Maybe they&amp;rsquo;ll be more obvious than I thought&lt;/td&gt;
&lt;td&gt;2019-02-06 22:17:54&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;Has anyone seen my Easter eggs?&lt;/td&gt;
&lt;td&gt;2019-01-07 22:47:54&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;I&amp;rsquo;m really late delivering these!&lt;/td&gt;
&lt;td&gt;2019-04-06 22:17:54&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;p&gt;Notice that, like the &lt;code&gt;person&lt;/code&gt; table, the &lt;code&gt;note&lt;/code&gt; table has a unique identifier called &lt;code&gt;note_id&lt;/code&gt;, which is the primary key for the &lt;code&gt;note&lt;/code&gt; table. One thing that isn&amp;rsquo;t obvious is the inclusion of the &lt;code&gt;person_id&lt;/code&gt; value in the table. What is that used for? This is what creates the relationship to the &lt;code&gt;person&lt;/code&gt; table. Whereas &lt;code&gt;note_id&lt;/code&gt; is the primary key for the table, &lt;code&gt;person_id&lt;/code&gt; is what&amp;rsquo;s known as a &lt;a href=&quot;https://en.wikipedia.org/wiki/Foreign_key&quot;&gt;foreign key&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The foreign key gives each entry in the &lt;code&gt;note&lt;/code&gt; table the primary key of the &lt;code&gt;person&lt;/code&gt; record it&amp;rsquo;s associated with. Using this, SQLAlchemy can gather all the notes associated with each person by connecting the &lt;code&gt;person.person_id&lt;/code&gt; primary key to the &lt;code&gt;note.person_id&lt;/code&gt; foreign key, creating a relationship.&lt;/p&gt;
&lt;h3 id=&quot;advantages_1&quot;&gt;Advantages&lt;/h3&gt;
&lt;p&gt;By breaking the data set into two tables, and introducing the concept of a foreign key, you&amp;rsquo;ve made the data a little more complex to think about, you have resolved the disadvantages of a single table representation. SQLAlchemy will help you encode the increased complexity fairly easily.&lt;/p&gt;
&lt;p&gt;The data is no longer redundant in the database. There is only one person entry for each person you want to store in the database. This solves the storage concern immediately and dramatically simplifies the maintenance concerns.&lt;/p&gt;
&lt;p&gt;If the Easter Bunny still wanted to change names, then you&amp;rsquo;d only have to change a single row in the &lt;code&gt;person&lt;/code&gt; table, and anything else related to that row (like the &lt;code&gt;note&lt;/code&gt; table) would immediately take advantage of the change. &lt;/p&gt;
&lt;p&gt;Column naming is more consistent and meaningful. Because person and note data exist in separate tables, the creation and update timestamp can be named consistently in both tables, as there is no conflict for names across tables.&lt;/p&gt;
&lt;p&gt;In addition, you&amp;rsquo;d no longer have to create permutations of each row for new one-to-many relationships you might want to represent. Take our &lt;code&gt;children&lt;/code&gt; and &lt;code&gt;phone_numbers&lt;/code&gt; example from earlier. Implementing this would require &lt;code&gt;child&lt;/code&gt; and &lt;code&gt;phone_number&lt;/code&gt; tables. Each table would contain a foreign key of &lt;code&gt;person_id&lt;/code&gt; relating it back to the &lt;code&gt;person&lt;/code&gt; table.&lt;/p&gt;
&lt;p&gt;Using SQLAlchemy, the data you&amp;rsquo;d get back from the above tables would be more immediately useful, as what you&amp;rsquo;d get is an object for each person row. That object has named attributes equivalent to the columns in the table. One of those attributes is a Python list containing the related note objects.&lt;/p&gt;
&lt;h3 id=&quot;disadvantages_1&quot;&gt;Disadvantages&lt;/h3&gt;
&lt;p&gt;Where the brute force approach was simpler to understand, the concept of foreign keys and relationships make thinking about the data somewhat more abstract. This abstraction needs to be thought about for every relationship you establish between tables. &lt;/p&gt;
&lt;p&gt;Making use of relationships means committing to using a database system. This is another tool to install, learn, and maintain above and beyond the application that actually uses the data.&lt;/p&gt;
&lt;h2 id=&quot;sqlalchemy-models&quot;&gt;SQLAlchemy Models&lt;/h2&gt;
&lt;p&gt;To use the two tables above, and the relationship between them, you&amp;rsquo;ll need to create SQLAlchemy models that are aware of both tables and the relationship between them. Here&amp;rsquo;s the SQLAlchemy &lt;code&gt;Person&lt;/code&gt; model from Part 2, updated to include a relationship to a collection of &lt;code&gt;notes&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight python&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;lineno&quot;&gt; 1 &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Person&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;db&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 2 &lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;__tablename__&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;person&amp;#39;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 3 &lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;person_id&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;db&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Column&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;db&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Integer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;primary_key&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 4 &lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;lname&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;db&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Column&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;db&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 5 &lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;fname&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;db&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Column&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;db&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 6 &lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;timestamp&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;db&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Column&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 7 &lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;db&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;DateTime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;datetime&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;utcnow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;onupdate&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;datetime&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;utcnow&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 8 &lt;/span&gt;    &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 9 &lt;/span&gt;&lt;span class=&quot;hll&quot;&gt;    &lt;span class=&quot;n&quot;&gt;notes&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;db&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;relationship&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;lineno&quot;&gt;10 &lt;/span&gt;&lt;span class=&quot;hll&quot;&gt;        &lt;span class=&quot;s1&quot;&gt;&amp;#39;Note&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;lineno&quot;&gt;11 &lt;/span&gt;&lt;span class=&quot;hll&quot;&gt;        &lt;span class=&quot;n&quot;&gt;backref&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;person&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;lineno&quot;&gt;12 &lt;/span&gt;&lt;span class=&quot;hll&quot;&gt;        &lt;span class=&quot;n&quot;&gt;cascade&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;all, delete, delete-orphan&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;lineno&quot;&gt;13 &lt;/span&gt;&lt;span class=&quot;hll&quot;&gt;        &lt;span class=&quot;n&quot;&gt;single_parent&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;lineno&quot;&gt;14 &lt;/span&gt;&lt;span class=&quot;hll&quot;&gt;        &lt;span class=&quot;n&quot;&gt;order_by&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;desc(Note.timestamp)&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;lineno&quot;&gt;15 &lt;/span&gt;&lt;span class=&quot;hll&quot;&gt;    &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Lines 1 to 8 of the above Python class look exactly like what you created before in Part 2. Lines 9 to 16 create a new attribute in the &lt;code&gt;Person&lt;/code&gt; class called &lt;code&gt;notes&lt;/code&gt;. This new &lt;code&gt;notes&lt;/code&gt; attributes is defined in the following lines of code:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Line 9:&lt;/strong&gt; Like the other attributes of the class, this line creates a new attribute called &lt;code&gt;notes&lt;/code&gt; and sets it equal to an instance of an object called &lt;code&gt;db.relationship&lt;/code&gt;. This object creates the relationship you&amp;rsquo;re adding to the &lt;code&gt;Person&lt;/code&gt; class and is created with all of the parameters defined in the lines that follow.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Line 10:&lt;/strong&gt; The string parameter &lt;code&gt;&#39;Note&#39;&lt;/code&gt; defines the SQLAlchemy class that the &lt;code&gt;Person&lt;/code&gt; class will be related to. The &lt;code&gt;Note&lt;/code&gt; class isn&amp;rsquo;t defined yet, which is why it&amp;rsquo;s a string here. This is a forward reference and helps handle problems that the order of definitions could cause when something is needed that isn&amp;rsquo;t defined until later in the code. The &lt;code&gt;&#39;Note&#39;&lt;/code&gt; string allows the &lt;code&gt;Person&lt;/code&gt; class to find the &lt;code&gt;Note&lt;/code&gt; class at runtime, which is after both &lt;code&gt;Person&lt;/code&gt; and &lt;code&gt;Note&lt;/code&gt; have been defined.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Line 11:&lt;/strong&gt; The &lt;code&gt;backref=&#39;person&#39;&lt;/code&gt; parameter is trickier. It creates what&amp;rsquo;s known as a backwards reference in &lt;code&gt;Note&lt;/code&gt; objects. Each instance of a &lt;code&gt;Note&lt;/code&gt; object will contain an attribute called &lt;code&gt;person&lt;/code&gt;. The &lt;code&gt;person&lt;/code&gt; attribute references the parent object that a particular &lt;code&gt;Note&lt;/code&gt; instance is associated with. Having a reference to the parent object (&lt;code&gt;person&lt;/code&gt; in this case) in the child can be very useful if your code iterates over notes and has to include information about the parent. This happens surprisingly often in display rendering code.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Line 12:&lt;/strong&gt; The &lt;code&gt;cascade=&#39;all, delete, delete-orphan&#39;&lt;/code&gt; parameter determines how to treat note object instances when changes are made to the parent &lt;code&gt;Person&lt;/code&gt; instance. For example, when a &lt;code&gt;Person&lt;/code&gt; object is deleted, SQLAlchemy will create the SQL necessary to delete the &lt;code&gt;Person&lt;/code&gt; from the database. Additionally, this parameter tells it to also delete all the &lt;code&gt;Note&lt;/code&gt; instances associated with it. You can read more about these options in the &lt;a href=&quot;https://docs.sqlalchemy.org/en/latest/orm/cascades.html#delete&quot;&gt;SQLAlchemy documentation&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Line 13:&lt;/strong&gt; The &lt;code&gt;single_parent=True&lt;/code&gt; parameter is required if &lt;code&gt;delete-orphan&lt;/code&gt; is part of the previous &lt;code&gt;cascade&lt;/code&gt; parameter. This tells SQLAlchemy not to allow orphaned &lt;code&gt;Note&lt;/code&gt; instances (a &lt;code&gt;Note&lt;/code&gt; without a parent &lt;code&gt;Person&lt;/code&gt; object) to exist because each &lt;code&gt;Note&lt;/code&gt; has a single parent.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Line 14:&lt;/strong&gt; The &lt;code&gt;order_by=&#39;desc(Note.timestamp)&#39;&lt;/code&gt; parameter tells SQLAlchemy how to sort the &lt;code&gt;Note&lt;/code&gt; instances associated with a &lt;code&gt;Person&lt;/code&gt;. When a &lt;code&gt;Person&lt;/code&gt; object is retrieved, by default the &lt;code&gt;notes&lt;/code&gt; attribute list will contain &lt;code&gt;Note&lt;/code&gt; objects in an unknown order. The SQLAlchemy &lt;code&gt;desc(...)&lt;/code&gt; function will sort the notes in descending order from newest to oldest. If this line was instead &lt;code&gt;order_by=&#39;Note.timestamp&#39;&lt;/code&gt;, SQLAlchemy would default to using the &lt;code&gt;asc(...)&lt;/code&gt; function, and sort the notes in ascending order, oldest to newest. &lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now that your &lt;code&gt;Person&lt;/code&gt; model has the new &lt;code&gt;notes&lt;/code&gt; attribute, and this represents the one-to-many relationship to &lt;code&gt;Note&lt;/code&gt; objects, you&amp;rsquo;ll need to define a SQLAlchemy model for a &lt;code&gt;Note&lt;/code&gt;: &lt;/p&gt;
&lt;div class=&quot;highlight python&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;lineno&quot;&gt; 1 &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Note&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;db&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 2 &lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;__tablename__&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;note&amp;#39;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 3 &lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;note_id&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;db&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Column&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;db&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Integer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;primary_key&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 4 &lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;person_id&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;db&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Column&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;db&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Integer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;db&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ForeignKey&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;person.person_id&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 5 &lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;content&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;db&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Column&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;db&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;nullable&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;False&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 6 &lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;timestamp&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;db&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Column&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 7 &lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;db&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;DateTime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;datetime&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;utcnow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;onupdate&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;datetime&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;utcnow&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 8 &lt;/span&gt;    &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;Note&lt;/code&gt; class defines the attributes making up a note as seen in our sample &lt;code&gt;note&lt;/code&gt; database table from above. The attributes are defined here:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Line 1&lt;/strong&gt; creates the &lt;code&gt;Note&lt;/code&gt; class, inheriting from &lt;code&gt;db.Model&lt;/code&gt;, exactly as you did before when creating the &lt;code&gt;Person&lt;/code&gt; class.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Line 2&lt;/strong&gt; tells the class what database table to use to store &lt;code&gt;Note&lt;/code&gt; objects.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Line 3&lt;/strong&gt; creates the &lt;code&gt;note_id&lt;/code&gt; attribute, defining it as an integer value, and as the primary key for the &lt;code&gt;Note&lt;/code&gt; object.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Line 4&lt;/strong&gt; creates the &lt;code&gt;person_id&lt;/code&gt; attribute, and defines it as the foreign key, relating the &lt;code&gt;Note&lt;/code&gt; class to the &lt;code&gt;Person&lt;/code&gt; class using the &lt;code&gt;person.person_id&lt;/code&gt; primary key. This, and the &lt;code&gt;Person.notes&lt;/code&gt; attribute, are how SQLAlchemy knows what to do when interacting with &lt;code&gt;Person&lt;/code&gt; and &lt;code&gt;Note&lt;/code&gt; objects.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Line 5&lt;/strong&gt; creates the &lt;code&gt;content&lt;/code&gt; attribute, which contains the actual text of the note. The &lt;code&gt;nullable=False&lt;/code&gt; parameter indicates that it&amp;rsquo;s okay to create new notes that have no content.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Line 6&lt;/strong&gt; creates the &lt;code&gt;timestamp&lt;/code&gt; attribute, and exactly like the &lt;code&gt;Person&lt;/code&gt; class, this contains the creation or update time for any particular &lt;code&gt;Note&lt;/code&gt; instance.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;initialize-the-database&quot;&gt;Initialize the Database&lt;/h2&gt;
&lt;p&gt;Now that you&amp;rsquo;ve updated the &lt;code&gt;Person&lt;/code&gt; and created the &lt;code&gt;Note&lt;/code&gt; models, you&amp;rsquo;ll use them to rebuild the testing database &lt;code&gt;people.db&lt;/code&gt;. You&amp;rsquo;ll do this by updating the &lt;code&gt;build_database.py&lt;/code&gt; code from Part 2. Here&amp;rsquo;s what the code will look like:&lt;/p&gt;
&lt;div class=&quot;highlight python&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;lineno&quot;&gt; 1 &lt;/span&gt;&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;os&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 2 &lt;/span&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;datetime&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;datetime&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 3 &lt;/span&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;config&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;db&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 4 &lt;/span&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;models&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Person&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Note&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 5 &lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 6 &lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;# Data to initialize database with&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 7 &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;PEOPLE&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 8 &lt;/span&gt;    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 9 &lt;/span&gt;        &lt;span class=&quot;s2&quot;&gt;&amp;quot;fname&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;Doug&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;10 &lt;/span&gt;        &lt;span class=&quot;s2&quot;&gt;&amp;quot;lname&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;Farrell&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;11 &lt;/span&gt;        &lt;span class=&quot;s2&quot;&gt;&amp;quot;notes&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;12 &lt;/span&gt;            &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;Cool, a mini-blogging application!&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;2019-01-06 22:17:54&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;13 &lt;/span&gt;            &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;This could be useful&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;2019-01-08 22:17:54&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;14 &lt;/span&gt;            &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;Well, sort of useful&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;2019-03-06 22:17:54&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;15 &lt;/span&gt;        &lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;16 &lt;/span&gt;    &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;17 &lt;/span&gt;    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;18 &lt;/span&gt;        &lt;span class=&quot;s2&quot;&gt;&amp;quot;fname&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;Kent&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;19 &lt;/span&gt;        &lt;span class=&quot;s2&quot;&gt;&amp;quot;lname&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;Brockman&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;20 &lt;/span&gt;        &lt;span class=&quot;s2&quot;&gt;&amp;quot;notes&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;21 &lt;/span&gt;            &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;22 &lt;/span&gt;                &lt;span class=&quot;s2&quot;&gt;&amp;quot;I&amp;#39;m going to make really profound observations&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;23 &lt;/span&gt;                &lt;span class=&quot;s2&quot;&gt;&amp;quot;2019-01-07 22:17:54&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;24 &lt;/span&gt;            &lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;25 &lt;/span&gt;            &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;26 &lt;/span&gt;                &lt;span class=&quot;s2&quot;&gt;&amp;quot;Maybe they&amp;#39;ll be more obvious than I thought&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;27 &lt;/span&gt;                &lt;span class=&quot;s2&quot;&gt;&amp;quot;2019-02-06 22:17:54&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;28 &lt;/span&gt;            &lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;29 &lt;/span&gt;        &lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;30 &lt;/span&gt;    &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;31 &lt;/span&gt;    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;32 &lt;/span&gt;        &lt;span class=&quot;s2&quot;&gt;&amp;quot;fname&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;Bunny&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;33 &lt;/span&gt;        &lt;span class=&quot;s2&quot;&gt;&amp;quot;lname&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;Easter&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;34 &lt;/span&gt;        &lt;span class=&quot;s2&quot;&gt;&amp;quot;notes&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;35 &lt;/span&gt;            &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;Has anyone seen my Easter eggs?&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;2019-01-07 22:47:54&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;36 &lt;/span&gt;            &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;I&amp;#39;m really late delivering these!&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;2019-04-06 22:17:54&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;37 &lt;/span&gt;        &lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;38 &lt;/span&gt;    &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;39 &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;40 &lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;41 &lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;# Delete database file if it exists currently&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;42 &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;exists&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;people.db&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;43 &lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;remove&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;people.db&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;44 &lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;45 &lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;# Create the database&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;46 &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;db&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;create_all&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;47 &lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;48 &lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;# Iterate over the PEOPLE structure and populate the database&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;49 &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;person&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PEOPLE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;50 &lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Person&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lname&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;person&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;lname&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fname&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;person&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;fname&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;51 &lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;52 &lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;# Add the notes for the person&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;53 &lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;note&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;person&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;notes&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;54 &lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;timestamp&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;note&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;55 &lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;notes&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;56 &lt;/span&gt;            &lt;span class=&quot;n&quot;&gt;Note&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;57 &lt;/span&gt;                &lt;span class=&quot;n&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;58 &lt;/span&gt;                &lt;span class=&quot;n&quot;&gt;timestamp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;datetime&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;strptime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;timestamp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;%Y-%m-&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%d&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; %H:%M:%S&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;59 &lt;/span&gt;            &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;60 &lt;/span&gt;        &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;61 &lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;db&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;session&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;62 &lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;63 &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;db&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;session&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;commit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The code above came from Part 2, with a few changes to create the one-to-many relationship between &lt;code&gt;Person&lt;/code&gt; and &lt;code&gt;Note&lt;/code&gt;. Here are the updated or new lines added to the code:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Line 4&lt;/strong&gt; has been updated to import the &lt;code&gt;Note&lt;/code&gt; class defined previously.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Lines 7 to 39&lt;/strong&gt; contain the updated &lt;code&gt;PEOPLE&lt;/code&gt; dictionary containing our person data, along with the list of notes associated with each person. This data will be inserted into the database.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Lines 49 to 61&lt;/strong&gt; iterate over the &lt;code&gt;PEOPLE&lt;/code&gt; dictionary, getting each &lt;code&gt;person&lt;/code&gt; in turn and using it to create a &lt;code&gt;Person&lt;/code&gt; object. &lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Line 53&lt;/strong&gt; iterates over the &lt;code&gt;person.notes&lt;/code&gt; list, getting each &lt;code&gt;note&lt;/code&gt; in turn.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Line 54&lt;/strong&gt; unpacks the &lt;code&gt;content&lt;/code&gt; and &lt;code&gt;timestamp&lt;/code&gt; from each &lt;code&gt;note&lt;/code&gt; tuple.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Line 55 to 60&lt;/strong&gt; creates a &lt;code&gt;Note&lt;/code&gt; object and appends it to the person notes collection using &lt;code&gt;p.notes.append()&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Line 61&lt;/strong&gt; adds the &lt;code&gt;Person&lt;/code&gt; object &lt;code&gt;p&lt;/code&gt; to the database session.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Line 63&lt;/strong&gt; commits all of the activity in the session to the database. It&amp;rsquo;s at this point that all of the data is written to the &lt;code&gt;person&lt;/code&gt; and &lt;code&gt;note&lt;/code&gt; tables in the &lt;code&gt;people.db&lt;/code&gt; database file.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You can see that working with the &lt;code&gt;notes&lt;/code&gt; collection in the &lt;code&gt;Person&lt;/code&gt; object instance &lt;code&gt;p&lt;/code&gt; is just like working with any other list in Python. SQLAlchemy takes care of the underlying one-to-many relationship information when the &lt;code&gt;db.session.commit()&lt;/code&gt; call is made.&lt;/p&gt;
&lt;p&gt;For example, just like a &lt;code&gt;Person&lt;/code&gt; instance has its primary key field &lt;code&gt;person_id&lt;/code&gt; initialized by SQLAlchemy when it&amp;rsquo;s committed to the database, instances of &lt;code&gt;Note&lt;/code&gt; will have their primary key fields initialized. In addition, the &lt;code&gt;Note&lt;/code&gt; foreign key &lt;code&gt;person_id&lt;/code&gt; will also be initialized with the primary key value of the &lt;code&gt;Person&lt;/code&gt; instance it&amp;rsquo;s associated with.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s an example instance of a &lt;code&gt;Person&lt;/code&gt; object before the &lt;code&gt;db.session.commit()&lt;/code&gt; in a kind of pseudocode:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;Person (
    person_id = None
    lname = &amp;#39;Farrell&amp;#39;
    fname = &amp;#39;Doug&amp;#39;
    timestamp = None
    notes = [
        Note (
            note_id = None
            person_id = None
            content = &amp;#39;Cool, a mini-blogging application!&amp;#39;
            timestamp = &amp;#39;2019-01-06 22:17:54&amp;#39;
        ),
        Note (
            note_id = None
            person_id = None
            content = &amp;#39;This could be useful&amp;#39;
            timestamp = &amp;#39;2019-01-08 22:17:54&amp;#39;
        ),
        Note (
            note_id = None
            person_id = None
            content = &amp;#39;Well, sort of useful&amp;#39;
            timestamp = &amp;#39;2019-03-06 22:17:54&amp;#39;
        )
    ]
)
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Here&amp;rsquo;s the example &lt;code&gt;Person&lt;/code&gt; object after the &lt;code&gt;db.session.commit()&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;Person (
    person_id = 1
    lname = &amp;#39;Farrell&amp;#39;
    fname = &amp;#39;Doug&amp;#39;
    timestamp = &amp;#39;2019-02-02 21:27:10.336&amp;#39;
    notes = [
        Note (
            note_id = 1
            person_id = 1
            content = &amp;#39;Cool, a mini-blogging application!&amp;#39;
            timestamp = &amp;#39;2019-01-06 22:17:54&amp;#39;
        ),
        Note (
            note_id = 2
            person_id = 1
            content = &amp;#39;This could be useful&amp;#39;
            timestamp = &amp;#39;2019-01-08 22:17:54&amp;#39;
        ),
        Note (
            note_id = 3
            person_id = 1
            content = &amp;#39;Well, sort of useful&amp;#39;
            timestamp = &amp;#39;2019-03-06 22:17:54&amp;#39;
        )
    ]
)
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The important difference between the two is that the primary key of the &lt;code&gt;Person&lt;/code&gt; and &lt;code&gt;Note&lt;/code&gt; objects has been initialized. The database engine took care of this as the objects were created because of the auto-incrementing feature of primary keys discussed in Part 2.&lt;/p&gt;
&lt;p&gt;Additionally, the &lt;code&gt;person_id&lt;/code&gt; foreign key in all the &lt;code&gt;Note&lt;/code&gt; instances has been initialized to reference its parent. This happens because of the order in which the &lt;code&gt;Person&lt;/code&gt; and &lt;code&gt;Note&lt;/code&gt; objects are created in the database. &lt;/p&gt;
&lt;p&gt;SQLAlchemy is aware of the relationship between &lt;code&gt;Person&lt;/code&gt; and &lt;code&gt;Note&lt;/code&gt; objects. When a &lt;code&gt;Person&lt;/code&gt; object is committed to the &lt;code&gt;person&lt;/code&gt; database table, SQLAlchemy gets the &lt;code&gt;person_id&lt;/code&gt; primary key value. That value is used to initialize the foreign key value of &lt;code&gt;person_id&lt;/code&gt; in a &lt;code&gt;Note&lt;/code&gt; object before it&amp;rsquo;s committed to the database.&lt;/p&gt;
&lt;p&gt;SQLAlchemy takes care of this database housekeeping work because of the information you passed when the &lt;code&gt;Person.notes&lt;/code&gt; attribute was initialized with the &lt;code&gt;db.relationship(...)&lt;/code&gt; object.&lt;/p&gt;
&lt;p&gt;In addition, the &lt;code&gt;Person.timestamp&lt;/code&gt; attribute has been initialized with the current timestamp.&lt;/p&gt;
&lt;p&gt;Running the &lt;code&gt;build_database.py&lt;/code&gt; program from the command line (in the &lt;a href=&quot;https://realpython.com/python-virtual-environments-a-primer/&quot;&gt;virtual environment&lt;/a&gt; will re-create the database with the new additions, getting it ready for use with the web application. This command line will rebuild the database:&lt;/p&gt;
&lt;div class=&quot;highlight sh&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; python build_database.py
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;build_database.py&lt;/code&gt; utility program doesn&amp;rsquo;t output any messages if it runs successfully. If it throws an exception, then an error will be printed on the screen.&lt;/p&gt;
&lt;h2 id=&quot;update-rest-api&quot;&gt;Update REST API&lt;/h2&gt;
&lt;p&gt;You&amp;rsquo;ve updated the SQLAlchemy models and used them to update the &lt;code&gt;people.db&lt;/code&gt; database. Now it&amp;rsquo;s time to update the REST API to provide access to the new notes information. Here&amp;rsquo;s the REST API you built in Part 2:&lt;/p&gt;
&lt;div class=&quot;table-responsive&quot;&gt;
&lt;table class=&quot;table table-hover&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Action&lt;/th&gt;
&lt;th&gt;HTTP Verb&lt;/th&gt;
&lt;th&gt;URL Path&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Create&lt;/td&gt;
&lt;td&gt;&lt;code&gt;POST&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/api/people&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;URL to create a new person&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Read&lt;/td&gt;
&lt;td&gt;&lt;code&gt;GET&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/api/people&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;URL to read a collection of people&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Read&lt;/td&gt;
&lt;td&gt;&lt;code&gt;GET&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/api/people/{person_id}&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;URL to read a single person by &lt;code&gt;person_id&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Update&lt;/td&gt;
&lt;td&gt;&lt;code&gt;PUT&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/api/people/{person_id}&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;URL to update an existing person by &lt;code&gt;person_id&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Delete&lt;/td&gt;
&lt;td&gt;&lt;code&gt;DELETE&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/api/people/{person_id}&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;URL to delete an existing person by &lt;code&gt;person_id&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;p&gt;The REST API above provides HTTP URL paths to collections of things, and to the things themselves. You can get a list of people or interact with a single person from that list of people. This path style refines what&amp;rsquo;s returned in a left-to-right manner, getting more granular as you go. &lt;/p&gt;
&lt;p&gt;You&amp;rsquo;ll continue this left-to-right pattern to get more granular and access the notes collections. Here&amp;rsquo;s the extended REST API you&amp;rsquo;ll create in order to provide notes to the mini-blog web application:&lt;/p&gt;
&lt;div class=&quot;table-responsive&quot;&gt;
&lt;table class=&quot;table table-hover&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Action&lt;/th&gt;
&lt;th&gt;HTTP Verb&lt;/th&gt;
&lt;th&gt;URL Path&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Create&lt;/td&gt;
&lt;td&gt;&lt;code&gt;POST&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/api/people/{person_id}/notes&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;URL to create a new note&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Read&lt;/td&gt;
&lt;td&gt;&lt;code&gt;GET&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/api/people/{person_id}/notes/{note_id}&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;URL to read a single person&amp;rsquo;s single note&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Update&lt;/td&gt;
&lt;td&gt;&lt;code&gt;PUT&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;api/people/{person_id}/notes/{note_id}&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;URL to update a single person&amp;rsquo;s single note&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Delete&lt;/td&gt;
&lt;td&gt;&lt;code&gt;DELETE&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;api/people/{person_id}/notes/{note_id}&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;URL to delete a single person&amp;rsquo;s single note&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Read&lt;/td&gt;
&lt;td&gt;&lt;code&gt;GET&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/api/notes&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;URL to get all notes for all people sorted by &lt;code&gt;note.timestamp&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;p&gt;There are two variations in the &lt;code&gt;notes&lt;/code&gt; part of the REST API compared to the convention used in the &lt;code&gt;people&lt;/code&gt; section:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;There is no URL defined to get all the &lt;code&gt;notes&lt;/code&gt; associated with a person, only a URL to get a single note. This would have made the REST API complete in a way, but the web application you&amp;rsquo;ll create later doesn&amp;rsquo;t need this functionality. Therefore, it&amp;rsquo;s been left out.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;There is the inclusion of the last URL &lt;code&gt;/api/notes&lt;/code&gt;. This is a convenience method created for the web application. It will be used in the mini-blog on the home page to show all the notes in the system. There isn&amp;rsquo;t a way to get this information readily using the REST API pathing style as designed, so this &lt;strong&gt;shortcut&lt;/strong&gt; has been added.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;As in Part 2, the REST API is configured in the &lt;a href=&quot;https://github.com/realpython/materials/blob/master/flask-connexion-rest-part-3/swagger.yml&quot;&gt;&lt;code&gt;swagger.yml&lt;/code&gt;&lt;/a&gt; file.&lt;/p&gt;
&lt;div class=&quot;alert alert-primary&quot; role=&quot;alert&quot;&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The idea of designing a REST API with a path that gets more and more granular as you move from left to right is very useful. Thinking this way can help clarify the relationships between different parts of a database. Just be aware that there are realistic limits to how far down a hierarchical structure this kind of design should be taken. &lt;/p&gt;
&lt;p&gt;For example, what if the &lt;code&gt;Note&lt;/code&gt; object had a collection of its own, something like comments on the notes. Using the current design ideas, this would lead to a URL that went something like this: &lt;code&gt;/api/people/{person_id}/notes/{note_id}/comments/{comment_id}&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;There is no practical limit to this kind of design, but there is one for usefulness. In actual use in real applications, a long, multilevel URL like that one is hardly ever needed. A more common pattern is to get a list of intervening objects (like notes) and then use a separate API entry point to get a single comment for an application use case.&lt;/p&gt;
&lt;/div&gt;
&lt;h2 id=&quot;implement-the-api&quot;&gt;Implement the API&lt;/h2&gt;
&lt;p&gt;With the updated REST API defined in the &lt;code&gt;swagger.yml&lt;/code&gt; file, you&amp;rsquo;ll need to update the implementation provided by the Python modules. This means updating existing module files, like &lt;code&gt;models.py&lt;/code&gt; and &lt;code&gt;people.py&lt;/code&gt;, and creating a new module file called &lt;code&gt;notes.py&lt;/code&gt; to implement support for &lt;code&gt;Notes&lt;/code&gt; in the extended REST API.&lt;/p&gt;
&lt;h3 id=&quot;update-response-json&quot;&gt;Update Response JSON&lt;/h3&gt;
&lt;p&gt;The purpose of the REST API is to get useful JSON data out of the database. Now that you&amp;rsquo;ve updated the SQLAlchemy &lt;code&gt;Person&lt;/code&gt; and created the &lt;code&gt;Note&lt;/code&gt; models, you&amp;rsquo;ll need to update the Marshmallow schema models as well. As you may recall from Part 2, Marshmallow is the module that translates the SQLAlchemy objects into Python objects suitable for creating JSON strings. &lt;/p&gt;
&lt;p&gt;The updated and newly created Marshmallow schemas are in the &lt;code&gt;models.py&lt;/code&gt; module, which are explained below, and look like this:&lt;/p&gt;
&lt;div class=&quot;highlight python&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;lineno&quot;&gt; 1 &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;PersonSchema&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ma&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ModelSchema&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 2 &lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Meta&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 3 &lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;model&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Person&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 4 &lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;sqla_session&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;db&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;session&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 5 &lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;notes&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fields&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Nested&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;PersonNoteSchema&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[],&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;many&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 6 &lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 7 &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;PersonNoteSchema&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ma&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ModelSchema&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 8 &lt;/span&gt;    &lt;span class=&quot;sd&quot;&gt;&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 9 &lt;/span&gt;&lt;span class=&quot;sd&quot;&gt;    This class exists to get around a recursion issue&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;10 &lt;/span&gt;&lt;span class=&quot;sd&quot;&gt;    &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;11 &lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;note_id&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fields&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;12 &lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;person_id&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fields&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;13 &lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;content&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fields&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;14 &lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;timestamp&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fields&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;15 &lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;16 &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;NoteSchema&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ma&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ModelSchema&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;17 &lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Meta&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;18 &lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;model&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Note&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;19 &lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;sqla_session&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;db&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;session&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;20 &lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;person&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fields&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Nested&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;NotePersonSchema&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;21 &lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;22 &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;NotePersonSchema&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ma&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ModelSchema&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;23 &lt;/span&gt;    &lt;span class=&quot;sd&quot;&gt;&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;24 &lt;/span&gt;&lt;span class=&quot;sd&quot;&gt;    This class exists to get around a recursion issue&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;25 &lt;/span&gt;&lt;span class=&quot;sd&quot;&gt;    &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;26 &lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;person_id&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fields&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;27 &lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;lname&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fields&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;28 &lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;fname&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fields&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;29 &lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;timestamp&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fields&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;There are some interesting things going on in the above definitions. The &lt;code&gt;PersonSchema&lt;/code&gt; class has one new entry: the &lt;code&gt;notes&lt;/code&gt; attribute defined in line 5. This defines it as a nested relationship to the &lt;code&gt;PersonNoteSchema&lt;/code&gt;. It will default to an empty list if nothing is present in the SQLAlchemy &lt;code&gt;notes&lt;/code&gt; relationship. The &lt;code&gt;many=True&lt;/code&gt; parameter indicates that this is a one-to-many relationship, so Marshmallow will serialize all the related &lt;code&gt;notes&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;PersonNoteSchema&lt;/code&gt; class defines what a &lt;code&gt;Note&lt;/code&gt; object looks like as Marshmallow serializes the &lt;code&gt;notes&lt;/code&gt; list. The &lt;code&gt;NoteSchema&lt;/code&gt; defines what a SQLAlchemy &lt;code&gt;Note&lt;/code&gt; object looks like in terms of Marshmallow. Notice that it has a &lt;code&gt;person&lt;/code&gt; attribute. This attribute comes from the SQLAlchemy &lt;code&gt;db.relationship(...)&lt;/code&gt; definition parameter &lt;code&gt;backref=&#39;person&#39;&lt;/code&gt;. The &lt;code&gt;person&lt;/code&gt; Marshmallow definition is nested, but because it doesn&amp;rsquo;t have the &lt;code&gt;many=True&lt;/code&gt; parameter, there is only a single &lt;code&gt;person&lt;/code&gt; connected. &lt;/p&gt;
&lt;p&gt;The &lt;code&gt;NotePersonSchema&lt;/code&gt; class defines what is nested in the &lt;code&gt;NoteSchema.person&lt;/code&gt; attribute.&lt;/p&gt;
&lt;div class=&quot;alert alert-primary&quot; role=&quot;alert&quot;&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;You might be wondering why the &lt;code&gt;PersonSchema&lt;/code&gt; class has its own unique &lt;code&gt;PersonNoteSchema&lt;/code&gt; class to define the &lt;code&gt;notes&lt;/code&gt; collection attribute. By the same token, the &lt;code&gt;NoteSchema&lt;/code&gt; class has its own unique &lt;code&gt;NotePersonSchema&lt;/code&gt; class to define the &lt;code&gt;person&lt;/code&gt; attribute. You may be wondering whether the &lt;code&gt;PersonSchema&lt;/code&gt; class could be defined this way:&lt;/p&gt;
&lt;div class=&quot;highlight python&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;PersonSchema&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ma&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ModelSchema&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Meta&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;model&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Person&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;sqla_session&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;db&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;session&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;notes&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fields&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Nested&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;NoteSchema&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[],&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;many&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Additionally, couldn&amp;rsquo;t the &lt;code&gt;NoteSchema&lt;/code&gt; class be defined using the &lt;code&gt;PersonSchema&lt;/code&gt; to define the &lt;code&gt;person&lt;/code&gt; attribute? A class definition like this would each refer to the other, and this causes a recursion error in Marshmallow as it will cycle from &lt;code&gt;PersonSchema&lt;/code&gt; to &lt;code&gt;NoteSchema&lt;/code&gt; until it runs out of stack space. Using the unique schema references breaks the recursion and allows this kind of nesting to work.&lt;/p&gt;
&lt;/div&gt;
&lt;h3 id=&quot;people&quot;&gt;People&lt;/h3&gt;
&lt;p&gt;Now that you&amp;rsquo;ve got the schemas in place to work with the one-to-many relationship between &lt;code&gt;Person&lt;/code&gt; and &lt;code&gt;Note&lt;/code&gt;, you need to update the &lt;code&gt;person.py&lt;/code&gt; and create the &lt;code&gt;note.py&lt;/code&gt; modules in order to implement a working REST API.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;people.py&lt;/code&gt; module needs two changes. The first is to import the &lt;code&gt;Note&lt;/code&gt; class, along with the &lt;code&gt;Person&lt;/code&gt; class at the top of the module. Then only &lt;code&gt;read_one(person_id)&lt;/code&gt; needs to change in order to handle the relationship. That function will look like this:&lt;/p&gt;
&lt;div class=&quot;highlight python&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;lineno&quot;&gt; 1 &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;read_one&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;person_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 2 &lt;/span&gt;    &lt;span class=&quot;sd&quot;&gt;&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 3 &lt;/span&gt;&lt;span class=&quot;sd&quot;&gt;    This function responds to a request for /api/people/{person_id}&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 4 &lt;/span&gt;&lt;span class=&quot;sd&quot;&gt;    with one matching person from people&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 5 &lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 6 &lt;/span&gt;&lt;span class=&quot;sd&quot;&gt;    :param person_id:   Id of person to find&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 7 &lt;/span&gt;&lt;span class=&quot;sd&quot;&gt;    :return:            person matching id&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 8 &lt;/span&gt;&lt;span class=&quot;sd&quot;&gt;    &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 9 &lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;# Build the initial query&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;10 &lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;person&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;11 &lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;Person&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;query&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Person&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;person_id&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;person_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;12 &lt;/span&gt;&lt;span class=&quot;hll&quot;&gt;        &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;outerjoin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Note&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;lineno&quot;&gt;13 &lt;/span&gt;        &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;one_or_none&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;14 &lt;/span&gt;    &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;15 &lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;16 &lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;# Did we find a person?&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;17 &lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;person&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;18 &lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;19 &lt;/span&gt;        &lt;span class=&quot;c1&quot;&gt;# Serialize the data for the response&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;20 &lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;person_schema&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PersonSchema&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;21 &lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;person_schema&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dump&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;person&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;22 &lt;/span&gt;        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;23 &lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;24 &lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;# Otherwise, nope, didn&amp;#39;t find that person&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;25 &lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;26 &lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;abort&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;404&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;Person not found for Id: &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{person_id}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The only difference is line 12: &lt;code&gt;.outerjoin(Note)&lt;/code&gt;. An outer join (&lt;a href=&quot;https://en.wikipedia.org/wiki/Join_(SQL)#Left_outer_join&quot;&gt;left outer join&lt;/a&gt; in SQL terms) is necessary for the case where a user of the application has created a new &lt;code&gt;person&lt;/code&gt; object, which has no &lt;code&gt;notes&lt;/code&gt; related to it. The outer join ensures that the SQL query will return a &lt;code&gt;person&lt;/code&gt; object, even if there are no &lt;code&gt;note&lt;/code&gt; rows to join with.&lt;/p&gt;
&lt;p&gt;At the start of this article, you saw how person and note data could be represented in a single, flat table, and all of the disadvantages of that approach. You also saw the advantages of breaking that data up into two tables, &lt;code&gt;person&lt;/code&gt; and &lt;code&gt;note&lt;/code&gt;, with a relationship between them.&lt;/p&gt;
&lt;p&gt;Until now, we&amp;rsquo;ve been working with the data as two distinct, but related, items in the database. But now that you&amp;rsquo;re actually going to use the data, what we essentially want is for the data to be joined back together. This is what a &lt;a href=&quot;https://en.wikipedia.org/wiki/Join_(SQL)&quot;&gt;database join&lt;/a&gt; does. It combines data from two tables together using the primary key to foreign key relationship. &lt;/p&gt;
&lt;p&gt;A join is kind of a boolean &lt;code&gt;and&lt;/code&gt; operation because it only returns data if there is data in both tables to combine. If, for example, a &lt;code&gt;person&lt;/code&gt; row exists but has no related &lt;code&gt;note&lt;/code&gt; row, then there is nothing to join, so nothing is returned. This isn&amp;rsquo;t what you want for &lt;code&gt;read_one(person_id)&lt;/code&gt;. &lt;/p&gt;
&lt;p&gt;This is where the outer join comes in handy. It&amp;rsquo;s a kind of boolean &lt;code&gt;or&lt;/code&gt; operation. It returns &lt;code&gt;person&lt;/code&gt; data even if there is no associated &lt;code&gt;note&lt;/code&gt; data to combine with. This is the behavior you want for &lt;code&gt;read_one(person_id)&lt;/code&gt; to handle the case of a newly created &lt;code&gt;Person&lt;/code&gt; object that has no notes yet.&lt;/p&gt;
&lt;p&gt;You can see the complete &lt;a href=&quot;https://github.com/realpython/materials/blob/master/flask-connexion-rest-part-3/people.py&quot;&gt;&lt;code&gt;people.py&lt;/code&gt;&lt;/a&gt; in the article repository.&lt;/p&gt;
&lt;h3 id=&quot;notes&quot;&gt;Notes&lt;/h3&gt;
&lt;p&gt;You&amp;rsquo;ll create a &lt;code&gt;notes.py&lt;/code&gt; module to implement all the Python code associated with the new note related REST API definitions. In many ways, it works like the &lt;code&gt;people.py&lt;/code&gt; module, except it must handle both a &lt;code&gt;person_id&lt;/code&gt; and a &lt;code&gt;note_id&lt;/code&gt; as defined in the &lt;code&gt;swagger.yml&lt;/code&gt; configuration file. As an example, here is &lt;code&gt;read_one(person_id, note_id)&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight python&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;lineno&quot;&gt; 1 &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;read_one&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;person_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;note_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 2 &lt;/span&gt;    &lt;span class=&quot;sd&quot;&gt;&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 3 &lt;/span&gt;&lt;span class=&quot;sd&quot;&gt;    This function responds to a request for&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 4 &lt;/span&gt;&lt;span class=&quot;sd&quot;&gt;    /api/people/{person_id}/notes/{note_id}&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 5 &lt;/span&gt;&lt;span class=&quot;sd&quot;&gt;    with one matching note for the associated person&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 6 &lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 7 &lt;/span&gt;&lt;span class=&quot;sd&quot;&gt;    :param person_id:       Id of person the note is related to&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 8 &lt;/span&gt;&lt;span class=&quot;sd&quot;&gt;    :param note_id:         Id of the note&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 9 &lt;/span&gt;&lt;span class=&quot;sd&quot;&gt;    :return:                json string of note contents&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;10 &lt;/span&gt;&lt;span class=&quot;sd&quot;&gt;    &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;11 &lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;# Query the database for the note&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;12 &lt;/span&gt;&lt;span class=&quot;hll&quot;&gt;    &lt;span class=&quot;n&quot;&gt;note&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;lineno&quot;&gt;13 &lt;/span&gt;&lt;span class=&quot;hll&quot;&gt;        &lt;span class=&quot;n&quot;&gt;Note&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;query&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Person&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Person&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;person_id&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Note&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;person_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;lineno&quot;&gt;14 &lt;/span&gt;&lt;span class=&quot;hll&quot;&gt;        &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Person&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;person_id&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;person_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;lineno&quot;&gt;15 &lt;/span&gt;&lt;span class=&quot;hll&quot;&gt;        &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Note&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;note_id&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;note_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;lineno&quot;&gt;16 &lt;/span&gt;&lt;span class=&quot;hll&quot;&gt;        &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;one_or_none&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;lineno&quot;&gt;17 &lt;/span&gt;&lt;span class=&quot;hll&quot;&gt;    &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;lineno&quot;&gt;18 &lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;19 &lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;# Was a note found?&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;20 &lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;note&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;21 &lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;note_schema&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;NoteSchema&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;22 &lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;note_schema&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dump&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;note&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;23 &lt;/span&gt;        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;24 &lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;25 &lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;# Otherwise, nope, didn&amp;#39;t find that note&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;26 &lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;27 &lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;abort&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;404&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;Note not found for Id: &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{note_id}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The interesting parts of the above code are lines 12 to 17:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Line 13&lt;/strong&gt; begins a query against the &lt;code&gt;Note&lt;/code&gt; SQLAlchemy objects and joins to the related &lt;code&gt;Person&lt;/code&gt; SQLAlchemy object comparing &lt;code&gt;person_id&lt;/code&gt; from both &lt;code&gt;Person&lt;/code&gt; and &lt;code&gt;Note&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Line 14&lt;/strong&gt; filters the result down to the &lt;code&gt;Note&lt;/code&gt; objects that has a &lt;code&gt;Person.person_id&lt;/code&gt; equal to the passed in &lt;code&gt;person_id&lt;/code&gt; parameter.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Line 15&lt;/strong&gt; filters the result further to the &lt;code&gt;Note&lt;/code&gt; object that has a &lt;code&gt;Note.note_id&lt;/code&gt; equal to the passed in &lt;code&gt;note_id&lt;/code&gt; parameter.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Line 16&lt;/strong&gt; returns the &lt;code&gt;Note&lt;/code&gt; object if found, or &lt;code&gt;None&lt;/code&gt; if nothing matching the parameters is found.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You can check out the complete &lt;a href=&quot;https://github.com/realpython/materials/blob/master/flask-connexion-rest-part-3/notes.py&quot;&gt;&lt;code&gt;notes.py&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;updated-swagger-ui&quot;&gt;Updated Swagger UI&lt;/h2&gt;
&lt;p&gt;The Swagger UI has been updated by the action of updating the &lt;code&gt;swagger.yml&lt;/code&gt; file and creating the URL endpoint implementations. Below is a screenshot of the updated UI showing the Notes section with the &lt;code&gt;GET /api/people/{person_id}/notes/{note_id}&lt;/code&gt; expanded:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://files.realpython.com/media/swagger_ui_notes-part-3.bb51184454db.png&quot; target=&quot;_blank&quot;&gt;&lt;img class=&quot;img-fluid mx-auto d-block border &quot; src=&quot;https://files.realpython.com/media/swagger_ui_notes-part-3.bb51184454db.png&quot; width=&quot;1010&quot; height=&quot;970&quot; srcset=&quot;https://robocrop.realpython.net/?url=https%3A//files.realpython.com/media/swagger_ui_notes-part-3.bb51184454db.png&amp;amp;w=252&amp;amp;sig=7b37d3bcc0f224e9355abebb035342969b5b6479 252w, https://robocrop.realpython.net/?url=https%3A//files.realpython.com/media/swagger_ui_notes-part-3.bb51184454db.png&amp;amp;w=505&amp;amp;sig=aa31c4b5ba908b76dbe7e4ce8a99bb5e87f6a422 505w, https://files.realpython.com/media/swagger_ui_notes-part-3.bb51184454db.png 1010w&quot; sizes=&quot;75vw&quot; alt=&quot;Swagger UI with notes part 3&quot;/&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;mini-blogging-web-application&quot;&gt;Mini-Blogging Web Application&lt;/h2&gt;
&lt;p&gt;The web application has been substantially changed to show its new purpose as a mini-blogging application. It has three pages:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;The home page (&lt;code&gt;localhost:5000/&lt;/code&gt;)&lt;/strong&gt;, which shows all of the blog messages (notes) sorted from newest to oldest &lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;The people page (&lt;code&gt;localhost:5000/people&lt;/code&gt;)&lt;/strong&gt;, which shows all the people in the system, sorted by last name, and also allows the user to create a new person and update or delete an existing one&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;The notes page (&lt;code&gt;localhost:5000/people/{person_id}/notes&lt;/code&gt;)&lt;/strong&gt;, which shows all the notes associated with a person, sorted from newest to oldest, and also allows the user to create a new note and update or delete an existing one&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;navigation&quot;&gt;Navigation&lt;/h3&gt;
&lt;p&gt;There are two buttons on every page of the application:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;The &lt;em&gt;Home&lt;/em&gt; button&lt;/strong&gt; will navigate to the home screen.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The &lt;em&gt;People&lt;/em&gt; button&lt;/strong&gt; navigates to the &lt;code&gt;/people&lt;/code&gt; screen, showing all people in the database. &lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;These two buttons are present on every screen in the application as a way to get back to a starting point.&lt;/p&gt;
&lt;h3 id=&quot;home-page&quot;&gt;Home Page&lt;/h3&gt;
&lt;p&gt;Below is a screenshot of the home page showing the initialized database contents:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://files.realpython.com/media/flask_connexion_rest_home_page_part_3.049c149d887b.png&quot; target=&quot;_blank&quot;&gt;&lt;img class=&quot;img-fluid mx-auto d-block border &quot; src=&quot;https://files.realpython.com/media/flask_connexion_rest_home_page_part_3.049c149d887b.png&quot; width=&quot;1122&quot; height=&quot;415&quot; srcset=&quot;https://robocrop.realpython.net/?url=https%3A//files.realpython.com/media/flask_connexion_rest_home_page_part_3.049c149d887b.png&amp;amp;w=280&amp;amp;sig=cb3490b5c8499e04033d2309c66ea94171c3c000 280w, https://robocrop.realpython.net/?url=https%3A//files.realpython.com/media/flask_connexion_rest_home_page_part_3.049c149d887b.png&amp;amp;w=561&amp;amp;sig=49f96b84b9e39cf38844afcad3a21e56ecb9be8d 561w, https://files.realpython.com/media/flask_connexion_rest_home_page_part_3.049c149d887b.png 1122w&quot; sizes=&quot;75vw&quot; alt=&quot;Flask Connexion Rest Home Page Part 3&quot;/&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The functionality of this page works like this:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Double-clicking on a person&amp;rsquo;s name will take the user to the &lt;code&gt;/people/{person_id}&lt;/code&gt; page, with the editor section filled in with the person&amp;rsquo;s first and last names and the update and reset buttons enabled.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Double-clicking on a person&amp;rsquo;s note will take the user to the &lt;code&gt;/people/{person_id}/notes/{note_id}&lt;/code&gt; page, with the editor section filled in with the note&amp;rsquo;s contents and the &lt;em&gt;Update&lt;/em&gt; and &lt;em&gt;Reset&lt;/em&gt; buttons enabled.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;people-page&quot;&gt;People Page&lt;/h3&gt;
&lt;p&gt;Below is a screenshot of the people page showing the people in the initialized database:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://files.realpython.com/media/flask_connexion_rest_people_page_part_3.1ed575f1eeef.png&quot; target=&quot;_blank&quot;&gt;&lt;img class=&quot;img-fluid mx-auto d-block border &quot; src=&quot;https://files.realpython.com/media/flask_connexion_rest_people_page_part_3.1ed575f1eeef.png&quot; width=&quot;1117&quot; height=&quot;399&quot; srcset=&quot;https://robocrop.realpython.net/?url=https%3A//files.realpython.com/media/flask_connexion_rest_people_page_part_3.1ed575f1eeef.png&amp;amp;w=279&amp;amp;sig=7b4111145b525d22d4dd815453ced53dd9ec9e55 279w, https://robocrop.realpython.net/?url=https%3A//files.realpython.com/media/flask_connexion_rest_people_page_part_3.1ed575f1eeef.png&amp;amp;w=558&amp;amp;sig=e18ac9a3d7693475ffe17d09d4bbed8b3f8dc52a 558w, https://files.realpython.com/media/flask_connexion_rest_people_page_part_3.1ed575f1eeef.png 1117w&quot; sizes=&quot;75vw&quot; alt=&quot;Flask Connexion Rest People Page Part 3&quot;/&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The functionality of this page works like this:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Single-clicking on a person&amp;rsquo;s name will populate the editor section of the page with the person&amp;rsquo;s first and last name, disabling the &lt;em&gt;Create&lt;/em&gt; button, and enabling the &lt;em&gt;Update&lt;/em&gt; and &lt;em&gt;Delete&lt;/em&gt; buttons. &lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Double clicking on a person&amp;rsquo;s name will navigate to the notes pages for that person.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The functionality of the editor works like this:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;If the first and last name fields are empty, the &lt;em&gt;Create&lt;/em&gt; and &lt;em&gt;Reset&lt;/em&gt; buttons are enabled. Entering a new name in the fields and clicking &lt;em&gt;Create&lt;/em&gt; will create a new person and update the database and re-render the table below the editor. Clicking &lt;em&gt;Reset&lt;/em&gt; will clear the editor fields.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;If the first and last name fields have data, the user navigated here by double-clicking the person&amp;rsquo;s name from the home screen. In this case, the &lt;em&gt;Update&lt;/em&gt;, &lt;em&gt;Delete&lt;/em&gt;, and &lt;em&gt;Reset&lt;/em&gt; buttons are enabled. Changing the first or last name and clicking &lt;em&gt;Update&lt;/em&gt; will update the database and re-render the table below the editor. Clicking &lt;em&gt;Delete&lt;/em&gt; will remove the person from the database and re-render the table.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;notes-page&quot;&gt;Notes Page&lt;/h3&gt;
&lt;p&gt;Below is a screenshot of the notes page showing the notes for a person in the initialized database:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://files.realpython.com/media/flask_connexion_rest_notes_page_part_3.7f146b443cd9.png&quot; target=&quot;_blank&quot;&gt;&lt;img class=&quot;img-fluid mx-auto d-block border &quot; src=&quot;https://files.realpython.com/media/flask_connexion_rest_notes_page_part_3.7f146b443cd9.png&quot; width=&quot;1121&quot; height=&quot;452&quot; srcset=&quot;https://robocrop.realpython.net/?url=https%3A//files.realpython.com/media/flask_connexion_rest_notes_page_part_3.7f146b443cd9.png&amp;amp;w=280&amp;amp;sig=a7d9b4813bf1a5fe11fc4cdae7273c46f0ee12b3 280w, https://robocrop.realpython.net/?url=https%3A//files.realpython.com/media/flask_connexion_rest_notes_page_part_3.7f146b443cd9.png&amp;amp;w=560&amp;amp;sig=70be712d19df46579563beb0a077b72810b9cc77 560w, https://files.realpython.com/media/flask_connexion_rest_notes_page_part_3.7f146b443cd9.png 1121w&quot; sizes=&quot;75vw&quot; alt=&quot;Flask Connexion Rest Notes Page Part 3&quot;/&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The functionality of this page works like this:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Single-clicking on a note will populate the editor section of the page with the notes content, disabling the &lt;em&gt;Create&lt;/em&gt; button, and enabling the &lt;em&gt;Update&lt;/em&gt; and &lt;em&gt;Delete&lt;/em&gt; buttons. &lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;All other functionality of this page is in the editor section.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The functionality of the editor works like this:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;If the note content field is empty, then the &lt;em&gt;Create&lt;/em&gt; and &lt;em&gt;Reset&lt;/em&gt; buttons are enabled. Entering a new note in the field and clicking &lt;em&gt;Create&lt;/em&gt; will create a new note and update the database and re-render the table below the editor. Clicking &lt;em&gt;Reset&lt;/em&gt; will clear the editor fields.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;If the note field has data, the user navigated here by double-clicking the person&amp;rsquo;s note from the home screen. In this case, the &lt;em&gt;Update&lt;/em&gt;, &lt;em&gt;Delete&lt;/em&gt;, and &lt;em&gt;Reset&lt;/em&gt; buttons are enabled. Changing the note and clicking &lt;em&gt;Update&lt;/em&gt; will update the database and re-render the table below the editor. Clicking &lt;em&gt;Delete&lt;/em&gt; will remove the note from the database and re-render the table.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;web-application&quot;&gt;Web Application&lt;/h3&gt;
&lt;p&gt;This article is primarily focused on how to use SQLAlchemy to create relationships in the database, and how to extend the REST API to take advantage of those relationships. As such, the code for the web application didn&amp;rsquo;t get much attention. When you look at the web application code, keep an eye out for the following features:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Each page of the application is a fully formed &lt;a href=&quot;https://en.wikipedia.org/wiki/Single-page_application&quot;&gt;single page web application&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Each page of the application is driven by JavaScript following an &lt;a href=&quot;https://realpython.com/the-model-view-controller-mvc-paradigm-summarized-with-legos/&quot;&gt;MVC&lt;/a&gt; (Model/View/Controller) style of responsibility delegation.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The HTML that creates the pages takes advantage of the &lt;a href=&quot;http://jinja.pocoo.org/docs/2.10/templates/#template-inheritance&quot;&gt;Jinja2 inheritance functionality&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The hardcoded JavaScript table creation has been replaced by using the &lt;a href=&quot;https://handlebarsjs.com/&quot;&gt;Handlebars.js&lt;/a&gt; templating engine.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The timestamp formating in all of the tables is provided by &lt;a href=&quot;https://momentjs.com/&quot;&gt;Moment.js&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You can find the following code in the repository for this article:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The &lt;a href=&quot;https://github.com/realpython/materials/tree/master/flask-connexion-rest-part-3/templates&quot;&gt;HTML for the web application&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;The &lt;a href=&quot;https://github.com/realpython/materials/tree/master/flask-connexion-rest-part-3/static/css&quot;&gt;CSS for the web application&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;The &lt;a href=&quot;https://github.com/realpython/materials/tree/master/flask-connexion-rest-part-3/static/js&quot;&gt;JavaScript for the web application&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;All of the example code for this article is available in the &lt;a href=&quot;https://github.com/realpython/materials/tree/master/flask-connexion-rest-part-3&quot;&gt;GitHub repository&lt;/a&gt; for this article. This contains all of the code related to this article, including all of the web application code.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Congratulations are in order for what you&amp;rsquo;ve learned in this article! Knowing how to build and use database relationships gives you a powerful tool to solve many difficult problems. There are other relationship besides the one-to-many example from this article. Other common ones are &lt;a href=&quot;https://en.wikipedia.org/wiki/One-to-one_(data_model)&quot;&gt;one-to-one&lt;/a&gt;, &lt;a href=&quot;https://en.wikipedia.org/wiki/Many-to-many_(data_model)&quot;&gt;many-to-many&lt;/a&gt;, and &lt;a href=&quot;https://www.ibm.com/support/knowledgecenter/en/SSWU4L/Data/imc_Data/Data_q_a_watson_assistant/What_is_a_many-to-one_relationship.html&quot;&gt;many-to-one&lt;/a&gt;. All of them have a place in your toolbelt, and SQLAlchemy can help you tackle them all!&lt;/p&gt;
&lt;p&gt;For more information about databases, you can check out &lt;a href=&quot;https://realpython.com/tutorials/databases/&quot;&gt;these tutorials&lt;/a&gt;. You can also &lt;a href=&quot;https://realpython.com/flask-by-example-part-2-postgres-sqlalchemy-and-alembic/&quot;&gt;set up Flask&lt;/a&gt; to use SQLAlchemy. You can check out &lt;a href=&quot;https://realpython.com/the-model-view-controller-mvc-paradigm-summarized-with-legos/&quot;&gt;Model-View-Controller (MVC)&lt;/a&gt; more information about the pattern used in the web application JavaScript code.&lt;/p&gt;
&lt;p&gt;In Part 4 of this series, you&amp;rsquo;ll focus on the HTML, CSS, and JavaScript files used to create the web application.&lt;/p&gt;
&lt;div class=&quot;container py-3 series-nav mb-3&quot;&gt;
  &lt;div class=&quot;row justify-content-between&quot;&gt;
    &lt;div class=&quot;col-12 col-md-3 text-left text-muted ml-1&quot;&gt;&lt;a href=&quot;https://realpython.com/flask-connexion-rest-api-part-2/&quot;&gt; «&amp;nbsp;Part 2: Database Persistence&lt;/a&gt;&lt;/div&gt;
    &lt;div class=&quot;col-12 col-md-3 text-center text-muted&quot;&gt;&lt;a href=&quot;#&quot;&gt;Part 3: Database Relationships&lt;/a&gt;&lt;/div&gt;
    &lt;div class=&quot;col-12 col-md-3 text-right text-muted mr-1&quot;&gt;&lt;a &gt;Part 4: Coming Soon!&amp;nbsp;»&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;
        &lt;hr /&gt;
        &lt;p&gt;&lt;em&gt;[ Improve Your Python With 🐍 Python Tricks 💌 – Get a short &amp;amp; sweet Python Trick delivered to your inbox every couple of days. &lt;a href=&quot;https://realpython.com/python-tricks/?utm_source=realpython&amp;amp;utm_medium=rss&amp;amp;utm_campaign=footer&quot;&gt;&amp;gt;&amp;gt; Click here to learn more and see examples&lt;/a&gt; ]&lt;/em&gt;&lt;/p&gt;
      </content>
    </entry>
  
    <entry>
      <title>Python Development in Visual Studio Code (Setup Guide)</title>
      <id>https://realpython.com/courses/python-development-visual-studio-code-setup-guide/</id>
      <link href="https://realpython.com/courses/python-development-visual-studio-code-setup-guide/"/>
      <updated>2019-04-04T14:00:00+00:00</updated>
      <summary>Learn how to set up Visual Studio Code for Python development. By following examples, you&#39;ll cover everything from  installing and configuring VSCode, to running tests and debugging Python apps.</summary>
      <content type="html">
        &lt;p&gt;Learn how to set up Visual Studio Code for Python development. By following examples, you&amp;rsquo;ll cover everything from  installing and configuring VSCode, to running tests and debugging Python apps. Make the most of this powerful Python IDE by following our complete setup guide.&lt;/p&gt;
        &lt;hr /&gt;
        &lt;p&gt;&lt;em&gt;[ Improve Your Python With 🐍 Python Tricks 💌 – Get a short &amp;amp; sweet Python Trick delivered to your inbox every couple of days. &lt;a href=&quot;https://realpython.com/python-tricks/?utm_source=realpython&amp;amp;utm_medium=rss&amp;amp;utm_campaign=footer&quot;&gt;&amp;gt;&amp;gt; Click here to learn more and see examples&lt;/a&gt; ]&lt;/em&gt;&lt;/p&gt;
      </content>
    </entry>
  
    <entry>
      <title>What Is Pip? A Guide for New Pythonistas</title>
      <id>https://realpython.com/what-is-pip/</id>
      <link href="https://realpython.com/what-is-pip/"/>
      <updated>2019-04-03T14:00:00+00:00</updated>
      <summary>What is pip? In this beginner-friendly tutorial, you&#39;ll learn how to use pip, the standard package manager for Python, so that you can install and manage additional packages that are not part of the Python standard library.</summary>
      <content type="html">
        &lt;p&gt;What is &lt;code&gt;pip&lt;/code&gt;? &lt;a href=&quot;https://pip.pypa.io/en/stable/&quot;&gt;&lt;code&gt;pip&lt;/code&gt;&lt;/a&gt; is the standard package manager for &lt;a href=&quot;https://www.python.org/&quot;&gt;Python&lt;/a&gt;. It allows you to install and manage additional packages that are not part of the &lt;a href=&quot;https://docs.python.org/3/py-modindex.html&quot;&gt;Python standard library&lt;/a&gt;. This tutorial is an introduction to &lt;code&gt;pip&lt;/code&gt; for new Pythonistas.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;In this tutorial, you&amp;rsquo;ll learn about:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Installing additional packages not included with the standard Python distribution&lt;/li&gt;
&lt;li&gt;Finding packages published to the &lt;a href=&quot;https://pypi.org/&quot;&gt;Python Package Index&lt;/a&gt; (&lt;a href=&quot;https://pypi.org/&quot;&gt;PyPI&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Managing requirements for your scripts and applications&lt;/li&gt;
&lt;li&gt;Uninstalling packages and their dependencies&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As you&amp;rsquo;ll see, the Python community is very active and has created some neat alternatives to &lt;code&gt;pip&lt;/code&gt; that you&amp;rsquo;ll learn about later in this tutorial.&lt;/p&gt;
&lt;div class=&quot;alert alert-warning&quot; role=&quot;alert&quot;&gt;&lt;p&gt;&lt;strong&gt;Free Bonus:&lt;/strong&gt; &lt;a href=&quot;&quot; class=&quot;alert-link&quot; data-toggle=&quot;modal&quot; data-target=&quot;#modal-python-mastery-course&quot; data-focus=&quot;false&quot;&gt;5 Thoughts On Python Mastery&lt;/a&gt;, a free course for Python developers that shows you the roadmap and the mindset you&#39;ll need to take your Python skills to the next level.&lt;/p&gt;&lt;/div&gt;

&lt;h2 id=&quot;getting-started-with-pip&quot;&gt;Getting Started With &lt;code&gt;pip&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;So, what is pip? &lt;code&gt;pip&lt;/code&gt; is a package manager for Python. That means it&amp;rsquo;s a tool that allows you to install and manage additional libraries and dependencies that are not distributed as part of the standard library. &lt;/p&gt;
&lt;p&gt;Package management is so important that &lt;code&gt;pip&lt;/code&gt; has been included with the Python installer since versions &lt;code&gt;3.4&lt;/code&gt; for Python 3 and &lt;code&gt;2.7.9&lt;/code&gt; for Python 2, and it&amp;rsquo;s used by many Python projects, which makes it an essential tool for every Pythonista.&lt;/p&gt;
&lt;p&gt;The concept of a package manager might be familiar to you if you are coming from other languages. &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript&quot;&gt;JavaScript&lt;/a&gt; uses &lt;a href=&quot;https://www.npmjs.com/&quot;&gt;&lt;code&gt;npm&lt;/code&gt;&lt;/a&gt; for package management, &lt;a href=&quot;https://www.ruby-lang.org/en/&quot;&gt;Ruby&lt;/a&gt; uses &lt;a href=&quot;https://rubygems.org/&quot;&gt;gem&lt;/a&gt;, and &lt;a href=&quot;https://dotnet.microsoft.com/languages&quot;&gt;.NET&lt;/a&gt; use &lt;a href=&quot;https://www.nuget.org/&quot;&gt;NuGet&lt;/a&gt;. In Python, &lt;code&gt;pip&lt;/code&gt; has become the standard package manager.&lt;/p&gt;
&lt;p&gt;The Python installer installs &lt;code&gt;pip&lt;/code&gt;, so it should be ready for you to use, unless you installed an old version of Python. You can verify that &lt;code&gt;pip&lt;/code&gt; is available by running the following command in your console:&lt;/p&gt;
&lt;div class=&quot;highlight sh&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; pip --version

&lt;span class=&quot;go&quot;&gt;pip 18.1 from C:\Python37\lib\site-packages\pip (python 3.7)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You should see a similar output displaying the &lt;code&gt;pip&lt;/code&gt; version, as well as the location and version of Python. If you are using an old version of Python that does not include &lt;code&gt;pip&lt;/code&gt;, then you can install it by following the instructions for your system in the &lt;a href=&quot;https://pip.pypa.io/en/stable/installing/&quot;&gt;&lt;code&gt;pip&lt;/code&gt; installation documentation&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;You probably want to follow the examples in this tutorial inside a virtual environment to avoid installing packages to the global Python installation. You can learn about virtual environments in &lt;a href=&quot;https://realpython.com/python-virtual-environments-a-primer/&quot;&gt;Python Virtual Environments: A Primer&lt;/a&gt;. The &lt;a href=&quot;https://realpython.com/python-virtual-environments-a-primer/#using-virtual-environments&quot;&gt;Using Virtual Environments&lt;/a&gt; section of that article explains the basics of creating new virtual environments.&lt;/p&gt;
&lt;h2 id=&quot;installing-packages-with-pip&quot;&gt;Installing Packages With &lt;code&gt;pip&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;Python is considered a &lt;a href=&quot;https://www.python.org/dev/peps/pep-0206/#id3&quot;&gt;batteries included&lt;/a&gt; language. This means that the &lt;a href=&quot;https://docs.python.org/3/py-modindex.html&quot;&gt;Python standard library&lt;/a&gt; includes an extensive set of packages and modules to help developers with their scripts and applications.&lt;/p&gt;
&lt;p&gt;At the same time, Python has a very active community that contributes an even bigger set of packages that can help you with your development needs. These packages are published to the &lt;a href=&quot;https://pypi.org/&quot;&gt;Python Package Index&lt;/a&gt;, also known as &lt;a href=&quot;https://pypi.org/&quot;&gt;PyPI&lt;/a&gt; (pronounced &lt;em&gt;Pie Pea Eye&lt;/em&gt;). PyPI hosts an extensive collection of packages that include development frameworks, tools, and libraries. &lt;/p&gt;
&lt;p&gt;Many of these packages simplify Python development by providing friendly interfaces to functionality that already exists in the standard library. For example, you can write a script that retrieves the contents of a web page using only the standard libraries included with Python:&lt;/p&gt;
&lt;div class=&quot;highlight python&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;# In using-http.py&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;cgi&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;http.client&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;server&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;www.google.com&amp;#39;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;url&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;/&amp;#39;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;conn&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;client&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;HTTPSConnection&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;server&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;conn&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;GET&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;response&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;conn&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;getresponse&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;content_type&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;response&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;headers&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;Content-Type&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;params&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cgi&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;parse_header&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;content_type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;encoding&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;params&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;charset&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;response&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;read&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;text&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;decode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;encoding&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;nb&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;Response returned: &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{response.status}&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt; (&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{response.reason}&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;)&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;Body:&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In this script, you import &lt;code&gt;cgi&lt;/code&gt; and &lt;code&gt;http.client&lt;/code&gt;, both of which are included in the Python standard library. You create an &lt;code&gt;HTTPSConnection&lt;/code&gt; object specifying the server and invoke its &lt;code&gt;.request()&lt;/code&gt; and &lt;code&gt;.getresponse()&lt;/code&gt; to retrieve a response.&lt;/p&gt;
&lt;p&gt;From the response, you can retrieve the &lt;code&gt;Content-Type&lt;/code&gt; header and parse it using the &lt;code&gt;cgi&lt;/code&gt; module to extract the charset in which the page is encoded.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://docs.python.org/3/library/cgi.html#functions&quot;&gt;&lt;code&gt;cgi.parse_header()&lt;/code&gt;&lt;/a&gt; returns a tuple with a main value and a dictionary of parameters. For example, the &lt;code&gt;Content-Type&lt;/code&gt; header might contain a value like &lt;code&gt;text/html; charset=ISO-8859-1&lt;/code&gt;. &lt;/p&gt;
&lt;p&gt;The tuple will contain the string &lt;code&gt;text/html&lt;/code&gt; as the first element, and the second element will be a dictionary in the form &lt;code&gt;{&#39;charset&#39;: &#39;ISO-8859-1&#39;}&lt;/code&gt;. Because you only care about the &lt;code&gt;charset&lt;/code&gt; parameter, you can ignore the beginning of the tuple using an underscore: &lt;code&gt;_, params = cgi.parse_header(content_type)&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;alert alert-primary&quot; role=&quot;alert&quot;&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; &lt;a href=&quot;https://dbader.org/blog/meaning-of-underscores-in-python&quot;&gt;The Meaning of Underscores in Python&lt;/a&gt; explains how to use underscores to unpack values from a tuple.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;Once you have the encoding of the page, you can read the response and decode it into text. You can run the example in the console to see how it works:&lt;/p&gt;
&lt;div class=&quot;highlight sh&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; python using-http.py

&lt;span class=&quot;go&quot;&gt;Response returned: 200 (OK)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Body:&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;&amp;lt;!doctype html&amp;gt;&amp;lt;html itemscope=&amp;quot;&amp;quot; itemtype=&amp;quot;http://schema.org/WebPage&amp;quot; &lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;lang=&amp;quot;en&amp;quot;&amp;gt;&amp;lt;head&amp;gt;&amp;lt;meta content=&amp;quot;Search the world&amp;#39;s information, including &lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;webpages, images, videos and more. Google has many special features to help you &lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;find exactly what you&amp;#39;re looking for.&amp;quot; name=&amp;quot;description&amp;quot;&amp;gt;&amp;lt;meta content=&amp;quot;noodp&amp;quot; &lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;name=&amp;quot;robots&amp;quot;&amp;gt;... Additional Output Omitted&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This seems like a lot of work for a small script that retrieves the contents of a web page. Fortunately, there is a Python package that simplifies HTTP requests and provides a nice interface to do exactly what you want.&lt;/p&gt;
&lt;h3 id=&quot;basic-package-installation&quot;&gt;Basic Package Installation&lt;/h3&gt;
&lt;p&gt;PyPI hosts a very popular library to perform HTTP requests called &lt;a href=&quot;https://pypi.org/project/requests/&quot;&gt;&lt;code&gt;requests&lt;/code&gt;&lt;/a&gt;. You can learn all about it in its official &lt;a href=&quot;http://docs.python-requests.org/en/master/&quot;&gt;documentation site&lt;/a&gt;. &lt;/p&gt;
&lt;p&gt;The first step is to install the &lt;code&gt;requests&lt;/code&gt; package into your environment. You can learn about &lt;code&gt;pip&lt;/code&gt; supported commands by running it with &lt;code&gt;help&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight sh&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; pip &lt;span class=&quot;nb&quot;&gt;help&lt;/span&gt;

&lt;span class=&quot;go&quot;&gt;Usage:&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  pip &amp;lt;command&amp;gt; [options]&lt;/span&gt;

&lt;span class=&quot;go&quot;&gt;Commands:&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  install                     Install packages.&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  download                    Download packages.&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  uninstall                   Uninstall packages.&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  freeze                      Output installed packages in requirements format.&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  list                        List installed packages.&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  show                        Show information about installed packages.&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  check                       Verify installed packages have compatible &lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;                              dependencies.&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  config                      Manage local and global configuration.&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  search                      Search PyPI for packages.&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  wheel                       Build wheels from your requirements.&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  hash                        Compute hashes of package archives.&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  completion                  A helper command used for command completion.&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  help                        Show help for commands.&lt;/span&gt;

&lt;span class=&quot;go&quot;&gt;General Options:&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  -h, --help                  Show help.&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  --isolated                  Run pip in an isolated mode, ignoring environment &lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;                              variables and user configuration.&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  -v, --verbose               Give more output. Option is additive, and can be &lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;                              used up to 3 times.&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  -V, --version               Show version and exit.&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  -q, --quiet                 Give less output. Option is additive, and can be &lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;                              used up to 3 times (corresponding to WARNING, &lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;                              ERROR, and CRITICAL logging levels).&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  --log &amp;lt;path&amp;gt;                Path to a verbose appending log.&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  --proxy &amp;lt;proxy&amp;gt;             Specify a proxy in the form &lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;                              [user:passwd@]proxy.server:port.&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  --retries &amp;lt;retries&amp;gt;         Maximum number of retries each connection should &lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;                              attempt (default 5 times).&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  --timeout &amp;lt;sec&amp;gt;             Set the socket timeout (default 15 seconds).&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  --exists-action &amp;lt;action&amp;gt;    Default action when a path already exists: &lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;                              (s)witch, (i)gnore, (w)ipe, (b)ackup, (a)bort).&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  --trusted-host &amp;lt;hostname&amp;gt;   Mark this host as trusted, even though it does &lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;                              not have valid or any HTTPS.&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  --cert &amp;lt;path&amp;gt;               Path to alternate CA bundle.&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  --client-cert &amp;lt;path&amp;gt;        Path to SSL client certificate, a single file &lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;                              containing the private key and the certificate in &lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;                              PEM format.&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  --cache-dir &amp;lt;dir&amp;gt;           Store the cache data in &amp;lt;dir&amp;gt;.&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  --no-cache-dir              Disable the cache.&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  --disable-pip-version-check&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;                              Don&amp;#39;t periodically check PyPI to determine &lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;                              whether a new version of pip is available for &lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;                              download. Implied with --no-index.&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;As you can see, &lt;code&gt;pip&lt;/code&gt; provides an &lt;code&gt;install&lt;/code&gt; command to install packages. You can run it to install the &lt;code&gt;requests&lt;/code&gt; package:&lt;/p&gt;
&lt;div class=&quot;highlight sh&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; pip install requests

&lt;span class=&quot;go&quot;&gt;Looking in indexes: https://pypi.org/simple&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Collecting requests&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  Using cached &lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  https://files.pythonhosted.org/packages/7d/e3/&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  20f3d364d6c8e5d2353c72a67778eb189176f08e873c9900e10c0287b84b/&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  requests-2.21.0-py2.py3-none-any.whl&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Collecting chardet&amp;lt;3.1.0,&amp;gt;=3.0.2 (from requests)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  Using cached https://files.pythonhosted.org/packages/bc/a9/&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  01ffebfb562e4274b6487b4bb1ddec7ca55ec7510b22e4c51f14098443b8/&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  chardet-3.0.4-py2.py3-none-any.whl&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Collecting idna&amp;lt;2.9,&amp;gt;=2.5 (from requests)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  Using cached https://files.pythonhosted.org/packages/14/2c/&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  cd551d81dbe15200be1cf41cd03869a46fe7226e7450af7a6545bfc474c9/&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  idna-2.8-py2.py3-none-any.whl&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Collecting urllib3&amp;lt;1.25,&amp;gt;=1.21.1 (from requests)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  Using cached https://files.pythonhosted.org/packages/62/00/&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  ee1d7de624db8ba7090d1226aebefab96a2c71cd5cfa7629d6ad3f61b79e/&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  urllib3-1.24.1-py2.py3-none-any.whl&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Collecting certifi&amp;gt;=2017.4.17 (from requests)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  Using cached https://files.pythonhosted.org/packages/9f/e0/&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  accfc1b56b57e9750eba272e24c4dddeac86852c2bebd1236674d7887e8a/&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  certifi-2018.11.29-py2.py3-none-any.whl&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Installing collected packages: chardet, idna, urllib3, certifi, requests&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Successfully installed certifi-2018.11.29 chardet-3.0.4 idna-2.8 &lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  requests-2.21.0 urllib3-1.24.1&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;You are using pip version 18.1, however version 19.0.1 is available.&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;You should consider upgrading via the &amp;#39;python -m pip install --upgrade pip&amp;#39; &lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  command.&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You should see an output similar to the one above. You use &lt;code&gt;pip&lt;/code&gt; with an &lt;code&gt;install&lt;/code&gt; command followed by the name of the package you want to install. &lt;code&gt;pip&lt;/code&gt; looks for the package in PyPI, calculates its dependencies, and installs them to insure &lt;code&gt;requests&lt;/code&gt; will work.&lt;/p&gt;
&lt;p&gt;You can also see that the current environment is using &lt;code&gt;pip&lt;/code&gt; version &lt;code&gt;18.1&lt;/code&gt;, but version &lt;code&gt;19.0.1&lt;/code&gt; is available. It also shows the command you should use to update &lt;code&gt;pip&lt;/code&gt;, so let&amp;rsquo;s do that:&lt;/p&gt;
&lt;div class=&quot;highlight sh&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; python -m pip install --upgrade pip

&lt;span class=&quot;go&quot;&gt;Looking in indexes: https://pypi.org/simple&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Collecting pip&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  Downloading https://files.pythonhosted.org/packages/46/dc/&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  7fd5df840efb3e56c8b4f768793a237ec4ee59891959d6a215d63f727023/&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  pip-19.0.1-py2.py3-none-any.whl (1.4MB)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;    100% |████████████████████████████████| 1.4MB 2.0MB/s&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Installing collected packages: pip&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  Found existing installation: pip 18.1&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;    Uninstalling pip-18.1:&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;      Successfully uninstalled pip-18.1&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Successfully installed pip-19.0.1&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Notice that you use &lt;code&gt;python -m&lt;/code&gt; to update &lt;code&gt;pip&lt;/code&gt;. The &lt;code&gt;-m&lt;/code&gt; switch tells Python to run a module as an executable. This is necessary because in order for you to update &lt;code&gt;pip&lt;/code&gt;, the old version has to be uninstalled before installing the new version, and removing it while running the tool can cause errors.&lt;/p&gt;
&lt;p&gt;When you run &lt;code&gt;pip&lt;/code&gt; as a module, Python loads the module in memory and allows the package to be removed while it is being used. You can run packages as if they were scripts if the package provides a &lt;a href=&quot;https://docs.python.org/3/library/__main__.html&quot;&gt;top-level script&lt;/a&gt; &lt;code&gt;__main__.py&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Now that you have installed &lt;code&gt;requests&lt;/code&gt; and upgraded &lt;code&gt;pip&lt;/code&gt;, you can use the &lt;code&gt;list&lt;/code&gt; command to see the packages installed in your environment:&lt;/p&gt;
&lt;div class=&quot;highlight sh&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; pip list

&lt;span class=&quot;go&quot;&gt;Package    Version&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;---------- ----------&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;certifi    2018.11.29&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;chardet    3.0.4&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;idna       2.8&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;pip        19.0.1&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;requests   2.21.0&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;setuptools 40.6.2&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;urllib3    1.24.1&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;As you can see, &lt;code&gt;pip&lt;/code&gt; has been upgraded to version &lt;code&gt;19.0.1&lt;/code&gt; (the latest version at the moment), and &lt;code&gt;requests&lt;/code&gt; version &lt;code&gt;2.21.0&lt;/code&gt; has been installed.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;pip install &amp;lt;package&amp;gt;&lt;/code&gt; command always looks for the latest version of the package and installs it. It also searches for dependencies listed in the package metadata and installs those dependencies to insure that the package has all the requirements it needs. &lt;/p&gt;
&lt;p&gt;As you can see, multiple packages were installed. You can look at the package metadata by using the &lt;code&gt;show&lt;/code&gt; command in &lt;code&gt;pip&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight sh&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; pip show requests

&lt;span class=&quot;go&quot;&gt;Name: requests&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Version: 2.21.0&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Summary: Python HTTP for Humans.&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Home-page: http://python-requests.org&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Author: Kenneth Reitz&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Author-email: me@kennethreitz.org&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;License: Apache 2.0&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Location: py37\lib\site-packages&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Requires: certifi, chardet, idna, urllib3&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Required-by:&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The metadata lists &lt;code&gt;certifi&lt;/code&gt;, &lt;code&gt;chardet&lt;/code&gt;, &lt;code&gt;idna&lt;/code&gt;, and &lt;code&gt;urllib3&lt;/code&gt; as dependencies, and you can see they were also installed.&lt;/p&gt;
&lt;p&gt;With the &lt;code&gt;requests&lt;/code&gt; package installed, you can modify the example above and see how easy it is to retrieve the contents of a web page:&lt;/p&gt;
&lt;div class=&quot;highlight python&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;# In using-requests.py&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;requests&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;url&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;https://www.google.com&amp;#39;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;response&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;requests&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;Response returned: &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{response.status_code}&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{response.reason}&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;response&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You can import the &lt;code&gt;requests&lt;/code&gt; package as any other standard package because it is now installed in your environment. &lt;/p&gt;
&lt;p&gt;As you can see, &lt;code&gt;requests.get()&lt;/code&gt; handles the HTTP connection for you and returns a response object similar to the original example but with some interface improvements. &lt;/p&gt;
&lt;p&gt;You don&amp;rsquo;t have to deal with the encoding of the page because &lt;code&gt;requests&lt;/code&gt; will handle that for you in most situations. Still, &lt;code&gt;requests&lt;/code&gt; provides a flexible interface to handle special cases through the &lt;a href=&quot;http://docs.python-requests.org/en/master/user/quickstart/#response-content&quot;&gt;&lt;code&gt;requests.Response&lt;/code&gt;&lt;/a&gt; object.&lt;/p&gt;
&lt;h3 id=&quot;using-requirement-files&quot;&gt;Using Requirement Files&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;pip install&lt;/code&gt; command always installs the latest published version of a package, but sometimes, you may want to install a specific version that you know works with your code. &lt;/p&gt;
&lt;p&gt;You want to create a specification of the dependencies and versions you used to develop and test your application, so there are no surprises when you use the application in production.&lt;/p&gt;
&lt;p&gt;Requirement files allow you to specify exactly which packages and versions should be installed. Running &lt;code&gt;pip help&lt;/code&gt; shows that there is a &lt;code&gt;freeze&lt;/code&gt; command that outputs the installed packages in requirements format. You can use this command, redirecting the output to a file to generate a requirements file:&lt;/p&gt;
&lt;div class=&quot;highlight sh&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; pip freeze &amp;gt; requirements.txt
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; cat requirements.txt

&lt;span class=&quot;go&quot;&gt;certifi==2018.11.29&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;chardet==3.0.4&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;idna==2.8&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;requests==2.21.0&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;urllib3==1.24.1&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;freeze&lt;/code&gt; command dumps all the packages and their versions to standard output, so you can redirect the output to a file that can be used to install the exact requirements into another system. The convention is to name this file &lt;code&gt;requirements.txt&lt;/code&gt;, but you can give it any name you want.&lt;/p&gt;
&lt;p&gt;When you want to replicate the environment in another system, you can run &lt;code&gt;pip install&lt;/code&gt; specifying the requirements file using the &lt;code&gt;-r&lt;/code&gt; switch:&lt;/p&gt;
&lt;div class=&quot;highlight sh&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; pip install -r requirements.txt

&lt;span class=&quot;go&quot;&gt;Looking in indexes: https://pypi.org/simple&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Collecting certifi==2018.11.29 (from -r .\requirements.txt (line 1))&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  Using cached https://files.pythonhosted.org/packages/9f/e0/&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  accfc1b56b57e9750eba272e24c4dddeac86852c2bebd1236674d7887e8a/&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  certifi-2018.11.29-py2.py3-none-any.whl&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Collecting chardet==3.0.4 (from -r .\requirements.txt (line 2))&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  Using cached https://files.pythonhosted.org/packages/bc/a9/&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  01ffebfb562e4274b6487b4bb1ddec7ca55ec7510b22e4c51f14098443b8/&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  chardet-3.0.4-py2.py3-none-any.whl&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Collecting idna==2.8 (from -r .\requirements.txt (line 3))&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  Using cached https://files.pythonhosted.org/packages/14/2c/&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  cd551d81dbe15200be1cf41cd03869a46fe7226e7450af7a6545bfc474c9/&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  idna-2.8-py2.py3-none-any.whl&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Collecting requests==2.21.0 (from -r .\requirements.txt (line 4))&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  Using cached https://files.pythonhosted.org/packages/7d/e3/&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  20f3d364d6c8e5d2353c72a67778eb189176f08e873c9900e10c0287b84b/&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  requests-2.21.0-py2.py3-none-any.whl&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Collecting urllib3==1.24.1 (from -r .\requirements.txt (line 5))&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  Using cached https://files.pythonhosted.org/packages/62/00/&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  ee1d7de624db8ba7090d1226aebefab96a2c71cd5cfa7629d6ad3f61b79e/&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  urllib3-1.24.1-py2.py3-none-any.whl&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Installing collected packages: certifi, chardet, idna, urllib3, requests&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Successfully installed certifi-2018.11.29 chardet-3.0.4 idna-2.8 &lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  requests-2.21.0 urllib3-1.24.1&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The versions of the packages will match those listed in &lt;code&gt;requirements.txt&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight sh&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; pip list

&lt;span class=&quot;go&quot;&gt;Package    Version&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;---------- ----------&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;certifi    2018.11.29&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;chardet    3.0.4&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;idna       2.8&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;pip        19.0.1&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;requests   2.21.0&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;setuptools 40.6.2&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;urllib3    1.24.1&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You can submit the &lt;code&gt;requirements.txt&lt;/code&gt; file into source control and use it to create the exact environment in other machines.&lt;/p&gt;
&lt;h3 id=&quot;fine-tuning-requirements&quot;&gt;Fine-Tuning Requirements&lt;/h3&gt;
&lt;p&gt;The problem with &lt;strong&gt;hardcoding&lt;/strong&gt; the versions of your packages and their dependencies is that packages are updated frequently with bug and security fixes, and you probably want to leverage those as soon as they are published.&lt;/p&gt;
&lt;p&gt;The requirements file format allows you to specify dependency versions using logical operators that give you a bit of flexibility to insure packages are updated, but still define the base versions of a package.&lt;/p&gt;
&lt;p&gt;Open the &lt;code&gt;requirements.txt&lt;/code&gt; file in your favorite &lt;a href=&quot;https://realpython.com/python-ides-code-editors-guide/&quot;&gt;editor&lt;/a&gt; and make the following changes:&lt;/p&gt;
&lt;div class=&quot;highlight pyreq&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;certifi&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;=&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;2018.11&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;29&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;chardet&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;=&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;3.0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;idna&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;=&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;2.8&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;requests&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;=&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;2.21&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;urllib3&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;=&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;1.24&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You can change the logical operator to &lt;code&gt;&amp;gt;=&lt;/code&gt; to tell &lt;code&gt;pip&lt;/code&gt; to install an exact or greater version that has been published. When you set a new environment using the &lt;code&gt;requirments.txt&lt;/code&gt; file, &lt;code&gt;pip&lt;/code&gt; looks for the latest version that satisfies the requirement and installs it. You can upgrade the packages in your requirements file by running the &lt;code&gt;install&lt;/code&gt; command with the &lt;code&gt;--upgrade&lt;/code&gt; switch:&lt;/p&gt;
&lt;div class=&quot;highlight sh&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; pip install --upgrade -r requirements.txt

&lt;span class=&quot;go&quot;&gt;Looking in indexes: https://pypi.org/simple&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Requirement already up-to-date: certifi==2018.11.29 in \py37\lib\site-packages &lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  (from -r .\requirements.txt (line 1)) (2018.11.29)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Requirement already up-to-date: chardet==3.0.4 in \py37\lib\site-packages &lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  (from -r .\requirements.txt (line 2)) (3.0.4)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Requirement already up-to-date: idna==2.8 in \py37\lib\site-packages &lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  (from -r .\requirements.txt (line 3)) (2.8)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Requirement already up-to-date: requests==2.21.0 in \py37\lib\site-packages &lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  (from -r .\requirements.txt (line 4)) (2.21.0)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Requirement already up-to-date: urllib3==1.24.1 in \py37\lib\site-packages &lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  (from -r .\requirements.txt (line 5)) (1.24.1)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Nothing was upgraded because you have the latest versions, but if a new version was published for a listed package, then the package would&amp;rsquo;ve been upgraded.&lt;/p&gt;
&lt;p&gt;In an ideal world, new versions of packages would be backwards compatible and would never introduce new bugs. Unfortunately, new versions can introduce changes that will break your application. The requirements file syntax supports additional &lt;a href=&quot;https://www.python.org/dev/peps/pep-0440/#version-specifiers&quot;&gt;version specifiers&lt;/a&gt; to fine-tune your requirements.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s say that a new version &lt;code&gt;3.0&lt;/code&gt; of &lt;code&gt;requests&lt;/code&gt; is published but introduces an incompatible change that breaks your application. You can modify the requirements file to prevent &lt;code&gt;3.0&lt;/code&gt; or higher from being installed:&lt;/p&gt;
&lt;div class=&quot;highlight pyreq&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;certifi&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;=&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;2018.11&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;29&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;chardet&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;=&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;3.0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;idna&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;=&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;2.8&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;requests&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;=&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;2.21&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;3.0&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;urllib3&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;=&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;1.24&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Changing the version specifier for the &lt;code&gt;requests&lt;/code&gt; package ensures that any version greater or equal to &lt;code&gt;3.0&lt;/code&gt; does not get installed. The &lt;code&gt;pip&lt;/code&gt; documentation provides all the information about the &lt;a href=&quot;https://pip.pypa.io/en/stable/reference/pip_install/#requirements-file-format&quot;&gt;requirements file format&lt;/a&gt;, and you can consult it to learn more about it.&lt;/p&gt;
&lt;h3 id=&quot;production-vs-development-dependencies&quot;&gt;Production vs Development Dependencies&lt;/h3&gt;
&lt;p&gt;Not all packages that you install during the development of your applications are going to be application dependencies. There are many packages published to PyPI that are development tools or libraries that you want to leverage during the development process.&lt;/p&gt;
&lt;p&gt;As an example, you&amp;rsquo;ll probably want to unit test your application, so you need a unit test framework. A popular framework for unit testing is &lt;a href=&quot;https://docs.pytest.org/en/latest/&quot;&gt;&lt;code&gt;pytest&lt;/code&gt;&lt;/a&gt;. You want to install it in your development environment, but you do not want it in your production environment because it isn&amp;rsquo;t an application dependency.&lt;/p&gt;
&lt;p&gt;You create a second requirements file (&lt;code&gt;requirements_dev.txt&lt;/code&gt;) to list additional tools to set up a development environment:&lt;/p&gt;
&lt;div class=&quot;highlight pyreq&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;# In requirements_dev.txt&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;pytest&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;=&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;4.2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This requires you to use &lt;code&gt;pip&lt;/code&gt; to install both requirement files: &lt;code&gt;requirements.txt&lt;/code&gt; and &lt;code&gt;requirements_dev.txt&lt;/code&gt;. Fortunately, pip allows you to specify additional parameters within a requirements file. You can modify &lt;code&gt;requirements_dev.txt&lt;/code&gt; to also install the requirements from the production &lt;code&gt;requirements.txt&lt;/code&gt; file:&lt;/p&gt;
&lt;div class=&quot;highlight pyreq&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;# In requirements_dev.txt&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;r&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;requirements&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;txt&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;pytest&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;=&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;4.2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Notice that you are using the exact same &lt;code&gt;-r&lt;/code&gt; switch to install the production &lt;code&gt;requirements.txt&lt;/code&gt; file. The &lt;a href=&quot;https://pip.pypa.io/en/stable/reference/pip_install/#requirements-file-format&quot;&gt;requirements file format&lt;/a&gt; allows you to specify additional arguments right on a requirements file.&lt;/p&gt;
&lt;h3 id=&quot;freezing-requirements-for-production&quot;&gt;Freezing Requirements for Production&lt;/h3&gt;
&lt;p&gt;You created the production and development requirement files and added them to source control. The files use flexible version specifiers to ensure that you leverage bug fixes published by your dependencies. You are also testing your application and are ready to deploy it to production.&lt;/p&gt;
&lt;p&gt;You probably want to ensure that the versions of the dependencies you deploy to production are the exact same versions you used in your integration pipeline or build process because you know all the tests pass and the application works.&lt;/p&gt;
&lt;p&gt;The current version specifiers don&amp;rsquo;t guarantee that the same versions will be deployed to production, so you want to freeze the production requirements as you saw earlier.&lt;/p&gt;
&lt;p&gt;You create a clean production virtual environment and install the production requirements using the &lt;code&gt;requirements.txt&lt;/code&gt; file. Once the requirements are installed, you can freeze the specific versions, dumping the output to a &lt;code&gt;requirements_lock.txt&lt;/code&gt; file that you use in production. The &lt;code&gt;requirements_lock.txt&lt;/code&gt; file will contain exact versions specifiers and can be used to replicate the environment.&lt;/p&gt;
&lt;h2 id=&quot;finding-packages-to-use&quot;&gt;Finding Packages to Use&lt;/h2&gt;
&lt;p&gt;As you become a more experienced Pythonista, there&amp;rsquo;ll be a set of packages that you&amp;rsquo;ll know by heart and that you&amp;rsquo;ll use in most of your applications. The &lt;code&gt;requests&lt;/code&gt; and &lt;code&gt;pytest&lt;/code&gt; packages are good candidates to become useful tools in your Python toolbox.&lt;/p&gt;
&lt;p&gt;There will be times though when you will need to solve a different problem, and you will want to look for a different tool or library that can help you with it. As you can see above, &lt;code&gt;pip help&lt;/code&gt; shows that there is a &lt;code&gt;search&lt;/code&gt; command that looks for packages published to PyPI.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s see how this command can help us:&lt;/p&gt;
&lt;div class=&quot;highlight sh&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; pip &lt;span class=&quot;nb&quot;&gt;help&lt;/span&gt; search

&lt;span class=&quot;go&quot;&gt;Usage:&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  pip search [options] &amp;lt;query&amp;gt;&lt;/span&gt;

&lt;span class=&quot;go&quot;&gt;Description:&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  Search for PyPI packages whose name or summary contains &amp;lt;query&amp;gt;.&lt;/span&gt;

&lt;span class=&quot;go&quot;&gt;Search Options:&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  -i, --index &amp;lt;url&amp;gt;           Base URL of Python Package Index &lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;                              (default https://pypi.org/pypi)&lt;/span&gt;

&lt;span class=&quot;go&quot;&gt;General Options:&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  -h, --help                  Show help.&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  --isolated                  Run pip in an isolated mode, ignoring environment &lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;                              variables and user configuration.&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  -v, --verbose               Give more output. Option is additive, and can be &lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;                              used up to 3 times.&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  -V, --version               Show version and exit.&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  -q, --quiet                 Give less output. Option is additive, and can be &lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;                              used up to 3 times (corresponding to WARNING, &lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;                              ERROR, and CRITICAL logging levels).&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  --log &amp;lt;path&amp;gt;                Path to a verbose appending log.&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  --proxy &amp;lt;proxy&amp;gt;             Specify a proxy in the form &lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;                              [user:passwd@]proxy.server:port.&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  --retries &amp;lt;retries&amp;gt;         Maximum number of retries each connection should &lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;                              attempt (default 5 times).&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  --timeout &amp;lt;sec&amp;gt;             Set the socket timeout (default 15 seconds).&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  --exists-action &amp;lt;action&amp;gt;    Default action when a path already exists: &lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;                              (s)witch, (i)gnore, (w)ipe, (b)ackup, (a)bort).&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  --trusted-host &amp;lt;hostname&amp;gt;   Mark this host as trusted, even though it does &lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;                              not have valid or any HTTPS.&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  --cert &amp;lt;path&amp;gt;               Path to alternate CA bundle.&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  --client-cert &amp;lt;path&amp;gt;        Path to SSL client certificate, a single file &lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;                              containing the private key and the certificate in &lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;                              PEM format.&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  --cache-dir &amp;lt;dir&amp;gt;           Store the cache data in &amp;lt;dir&amp;gt;.&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  --no-cache-dir              Disable the cache.&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  --disable-pip-version-check&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;                              Don&amp;#39;t periodically check PyPI to determine &lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;                              whether a new version of pip is available for &lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;                              download. Implied with --no-index.&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  --no-color                  Suppress colored output&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The command takes a set of options listed above and a &lt;code&gt;&amp;lt;query&amp;gt;&lt;/code&gt;. The query is just a string to search for and will match packages and their descriptions.&lt;/p&gt;
&lt;div class=&quot;alert alert-primary&quot; role=&quot;alert&quot;&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; You can use &lt;code&gt;pip help &amp;lt;command&amp;gt;&lt;/code&gt; to retrieve additional information about a supported command.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;Let&amp;rsquo;s say your application needs to access a service that is using &lt;a href=&quot;https://oauth.net/2/&quot;&gt;OAuth2&lt;/a&gt; for authorization. Ideally, there is a library that works with &lt;code&gt;requests&lt;/code&gt; or with a similar interface that can help us. Let&amp;rsquo;s search PyPI for it using &lt;code&gt;pip&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight sh&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; pip search requests oauth

&lt;span class=&quot;go&quot;&gt;requests-oauth (0.4.1)             - Hook for adding Open Authentication &lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;                                     support to Python-requests HTTP library.&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;oauth (1.0.1)                      - Library for OAuth version 1.0a.&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;pmr2.oauth (0.6.1)                 - OAuth PAS Plugin, OAuth 1.0 provider for &lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;                                     Plone.&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;oauth-proxy (1.0.5)                - OAuth HTTP proxy&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;django-oauth (1.1)                 - Support of OAuth in Django.&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;intuit-oauth (1.2.0)               - Intuit OAuth Client&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;brubeck-oauth (0.1.11)             - Brubeck OAuth module&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;guillotina-oauth (2.0.0)           - guillotina oauth support&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;httpie-oauth (1.0.2)               - OAuth plugin for HTTPie.&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;paytm-oauth (0.2)                  - Consumer for paytm oauth&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;plurk-oauth (0.9.2)                - Plurk OAuth API&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;oauth-flow (1.0.3)                 - Authenticate and make calls to OAuth 1.0, &lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;                                     OAuth 2.0 services&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;... Additional Output Omitted&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The search term yields quite an extensive collection of packages. Some of them seem specific to a service or technology like &lt;code&gt;django-oauth&lt;/code&gt;. Others look promising, like &lt;code&gt;requests-oauth&lt;/code&gt;. Unfortunately, there isn&amp;rsquo;t much information other than a brief description.&lt;/p&gt;
&lt;p&gt;Most of the time, you want to search for packages directly in the &lt;a href=&quot;https://pypi.org/&quot;&gt;PyPI&lt;/a&gt; website. PyPI provides search capabilities for its index and a way to filter results by the metadata exposed in the package, like framework, topic, development status, and so on. &lt;/p&gt;
&lt;p&gt;A search for the same terms in PyPI yields a lot of results, but you can filter them by different categories. For example, you can expand the &lt;em&gt;Intended Audience&lt;/em&gt; and select &lt;em&gt;Developers&lt;/em&gt; since you want a library that helps you with developing your application. Also, you probably want a package that is stable and production-ready. You can expand the &lt;em&gt;Development Status&lt;/em&gt; category and select &lt;em&gt;Production/Stable&lt;/em&gt;:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://files.realpython.com/media/search_results.1151d72a4b9b.png&quot; target=&quot;_blank&quot;&gt;&lt;img class=&quot;img-fluid mx-auto d-block border &quot; src=&quot;https://files.realpython.com/media/search_results.1151d72a4b9b.png&quot; width=&quot;1473&quot; height=&quot;1471&quot; srcset=&quot;https://robocrop.realpython.net/?url=https%3A//files.realpython.com/media/search_results.1151d72a4b9b.png&amp;amp;w=368&amp;amp;sig=32d42daff402d9580b436e990f95d6e7df56aa04 368w, https://robocrop.realpython.net/?url=https%3A//files.realpython.com/media/search_results.1151d72a4b9b.png&amp;amp;w=736&amp;amp;sig=542bcb234bf41daed37fb0ced65cf2527f16b0f3 736w, https://files.realpython.com/media/search_results.1151d72a4b9b.png 1473w&quot; sizes=&quot;75vw&quot; alt=&quot;PyPi Search Results for Requests OAuth&quot;/&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;You can apply additional filters and tweak the search terms until you find the package that you are looking for.&lt;/p&gt;
&lt;p&gt;The results provide a link to the package page, which contains more information and hopefully some documentation. Let&amp;rsquo;s take a look at the information for &lt;code&gt;requests-oauth2&lt;/code&gt;:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://files.realpython.com/media/request_oauth_page.a5c341a27a69.png&quot; target=&quot;_blank&quot;&gt;&lt;img class=&quot;img-fluid mx-auto d-block border &quot; src=&quot;https://files.realpython.com/media/request_oauth_page.a5c341a27a69.png&quot; width=&quot;1474&quot; height=&quot;886&quot; srcset=&quot;https://robocrop.realpython.net/?url=https%3A//files.realpython.com/media/request_oauth_page.a5c341a27a69.png&amp;amp;w=368&amp;amp;sig=9004835381d13f007cf24fa1c54b1d1058a9fcbc 368w, https://robocrop.realpython.net/?url=https%3A//files.realpython.com/media/request_oauth_page.a5c341a27a69.png&amp;amp;w=737&amp;amp;sig=d02dbc0511342565f109618fa63d91e919569b2b 737w, https://files.realpython.com/media/request_oauth_page.a5c341a27a69.png 1474w&quot; sizes=&quot;75vw&quot; alt=&quot;PyPi Package Page for Requests OAuth 2&quot;/&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The project page provides more information, and it seems to have a link to the project homepage. The link takes you to the &lt;a href=&quot;https://github.com/maraujop/requests-oauth2&quot;&gt;project repository&lt;/a&gt; on GitHub. There, you can see some more information about the project and some usage examples.&lt;/p&gt;
&lt;p&gt;Finding the original source code repository can be an invaluable resource. There, you can find some hints about the status of the project by looking at the date of the latest commits, number of pull request and open issues, and so forth.&lt;/p&gt;
&lt;p&gt;Another option to find a package is to Google it. Widely used Python libraries will show up at the top of google searches, and you should be able to find a link to the package in PyPI or its source code repository.&lt;/p&gt;
&lt;p&gt;Finding the right package may take some time and research, but it will also speed up your development process once you find it.&lt;/p&gt;
&lt;h2 id=&quot;uninstalling-packages&quot;&gt;Uninstalling Packages&lt;/h2&gt;
&lt;p&gt;Once in a while, you will have to uninstall a package. You either found a better library to replace it, or it is something you don&amp;rsquo;t really need. Uninstalling packages can be a bit tricky.&lt;/p&gt;
&lt;p&gt;Notice that, when you installed &lt;code&gt;requests&lt;/code&gt;, &lt;code&gt;pip&lt;/code&gt; installed other dependencies too. The more packages you install, the bigger the chances that multiple packages depend on the same dependency. This is where the &lt;code&gt;show&lt;/code&gt; command in &lt;code&gt;pip&lt;/code&gt; comes in handy.&lt;/p&gt;
&lt;p&gt;Before you uninstall a package, make sure you run the &lt;code&gt;show&lt;/code&gt; command for that package:&lt;/p&gt;
&lt;div class=&quot;highlight sh&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; pip show requests

&lt;span class=&quot;go&quot;&gt;Name: requests&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Version: 2.21.0&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Summary: Python HTTP for Humans.&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Home-page: http://python-requests.org&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Author: Kenneth Reitz&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Author-email: me@kennethreitz.org&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;License: Apache 2.0&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Location: c:\users\isaac\projects\virtualenv\py37\lib\site-packages&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Requires: urllib3, certifi, chardet, idna&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Required-by:&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Notice the last two fields &lt;code&gt;Requires&lt;/code&gt; and &lt;code&gt;Required-by&lt;/code&gt;. The &lt;code&gt;show&lt;/code&gt; command tells us that &lt;code&gt;requests&lt;/code&gt; requires &lt;code&gt;urllib3&lt;/code&gt;, &lt;code&gt;certifi&lt;/code&gt;, &lt;code&gt;chardet&lt;/code&gt;, and &lt;code&gt;idna&lt;/code&gt;. You probably want to uninstall those two. You can also see that &lt;code&gt;requests&lt;/code&gt; is not required by any other package, so it is safe to uninstall it.&lt;/p&gt;
&lt;p&gt;You should run the &lt;code&gt;show&lt;/code&gt; command against all of the &lt;code&gt;requests&lt;/code&gt; dependencies to make sure that no other libraries also depend on them. Once you understand the dependency order of the packages you want to uninstall, you can remove them using the &lt;code&gt;uninstall&lt;/code&gt; command:&lt;/p&gt;
&lt;div class=&quot;highlight sh&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; pip uninstall certifi

&lt;span class=&quot;go&quot;&gt;Uninstalling certifi-2018.11.29:&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  Would remove:&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;    \py37\lib\site-packages\certifi-2018.11.29.dist-info\*&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;    \py37\lib\site-packages\certifi\*&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Proceed (y/n)? y&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  Successfully uninstalled certifi-2018.11.29&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Uninstalling a package shows you the files that will be removed and will ask for confirmation. If you are sure you want to remove the package because you&amp;rsquo;ve checked its dependencies and know that nothing else is using it, you can pass a &lt;code&gt;-y&lt;/code&gt; switch to suppress the file list and confirmation:&lt;/p&gt;
&lt;div class=&quot;highlight sh&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; pip uninstall urllib3 -y

&lt;span class=&quot;go&quot;&gt;Uninstalling urllib3-1.24.1:&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  Successfully uninstalled urllib3-1.24.1&lt;/span&gt;

&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; pip uninstall chardet -y

&lt;span class=&quot;go&quot;&gt;Uninstalling chardet-3.0.4:&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  Successfully uninstalled chardet-3.0.4&lt;/span&gt;

&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; pip uninstall idna -y

&lt;span class=&quot;go&quot;&gt;Uninstalling idna-2.8:&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  Successfully uninstalled idna-2.8&lt;/span&gt;

&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; pip uninstall requests -y

&lt;span class=&quot;go&quot;&gt;Uninstalling requests-2.21.0:&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  Successfully uninstalled requests-2.21.0&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You can specify all the packages you want to uninstall in a single call: &lt;code&gt;pip uninstall -y urllib3 chardet idna requests&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;You can also uninstall all the packages listed in a requirements file by providing the &lt;code&gt;-r &amp;lt;requirments file&amp;gt;&lt;/code&gt; option. The command will ask confirmation for each individual package, but you can suppress it, if you know what you&amp;rsquo;re doing, with the &lt;code&gt;-y&lt;/code&gt; switch:&lt;/p&gt;
&lt;div class=&quot;highlight sh&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; pip uninstall -r requirements.txt -y

&lt;span class=&quot;go&quot;&gt;Uninstalling certifi-2018.11.29:&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  Successfully uninstalled certifi-2018.11.29&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Uninstalling chardet-3.0.4:&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  Successfully uninstalled chardet-3.0.4&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Uninstalling idna-2.8:&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  Successfully uninstalled idna-2.8&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Uninstalling requests-2.21.0:&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  Successfully uninstalled requests-2.21.0&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Uninstalling urllib3-1.24.1:&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  Successfully uninstalled urllib3-1.24.1&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Remember to always check the dependencies of packages you want to uninstall. You probably want to uninstall all its dependencies, but uninstalling a package that is being used by others will break your application.&lt;/p&gt;
&lt;h2 id=&quot;alternatives-to-pip&quot;&gt;Alternatives to &lt;code&gt;pip&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;pip&lt;/code&gt; is an essential tool for all Pythonistas, and it is used by many applications and projects for package management. This tutorial has helped you with the basics, but the Python community is very active in providing great tools and libraries for other developers to use. These include other alternatives to &lt;code&gt;pip&lt;/code&gt; that try to simplify and improve package management.&lt;/p&gt;
&lt;p&gt;In this section, you&amp;rsquo;ll learn about other package management tools available for Python.&lt;/p&gt;
&lt;h3 id=&quot;conda-does-it-all&quot;&gt;Conda Does It All&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://conda.io/en/latest/&quot;&gt;Conda&lt;/a&gt; is a package, dependency, and environment manager for many languages including Python. In fact, its origin comes from &lt;a href=&quot;https://www.anaconda.com/&quot;&gt;Anaconda&lt;/a&gt;, which started as a data science package for Python.&lt;/p&gt;
&lt;p&gt;Conda is widely used for data science and machine learning applications, and uses its own &lt;a href=&quot;https://repo.continuum.io/&quot;&gt;index&lt;/a&gt; to host compatible packages. &lt;/p&gt;
&lt;p&gt;Conda not only allows you to manage package dependencies, but it also manages virtual environments for your applications, installs compatible Python distributions, and packages your application for deployment to production.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://realpython.com/python-windows-machine-learning-setup/&quot;&gt;Setting Up Python for Machine Learning on Windows&lt;/a&gt; is a great introduction to Conda that explores package and environment management. The only Windows-specific information is around installation, so it&amp;rsquo;s still relevant if you use a different OS platform.&lt;/p&gt;
&lt;h3 id=&quot;pipenv&quot;&gt;Pipenv&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://pipenv.readthedocs.io/en/latest/&quot;&gt;Pipenv&lt;/a&gt; is another package management tool that &amp;ldquo;aims to bring the best of all packaging worlds&amp;rdquo; to Python. It&amp;rsquo;s gaining a lot of traction among the Python community because it merges virtual environment and package management in a single tool.&lt;/p&gt;
&lt;p&gt;It also solves some of the most common hiccups you will run into when manually managing dependencies through &lt;code&gt;pip&lt;/code&gt;, like versions of packages, separating development and production dependencies, and locking versions for production.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://realpython.com/pipenv-guide/&quot;&gt;Pipenv: A Guide to the New Python Packaging Tool&lt;/a&gt; is a great start to learn about Pipenv and its approach to package management. Even though the article is tagged as &lt;code&gt;intermediate&lt;/code&gt;, the author does a great job of guiding the reader that the article is accessible to anyone starting with Python.&lt;/p&gt;
&lt;h3 id=&quot;poetry&quot;&gt;Poetry&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://poetry.eustace.io/&quot;&gt;Poetry&lt;/a&gt; is another &lt;code&gt;pip&lt;/code&gt; alternative that is gaining a lot of traction. Like Pipenv, it simplifies package version management and separates development vs production dependencies, and it works by isolating those dependencies into a virtual environment.&lt;/p&gt;
&lt;p&gt;If you are coming from &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript&quot;&gt;JavaScript&lt;/a&gt; and &lt;a href=&quot;https://www.npmjs.com/&quot;&gt;npm&lt;/a&gt;, then Poetry will look very familiar. It goes beyond package management, helping you build distributions for your applications and libraries and deploying them to PyPI. &lt;a href=&quot;https://realpython.com/pypi-publish-python-package/&quot;&gt;How to Publish an Open-Source Python Package to PyPI&lt;/a&gt; has a good &lt;a href=&quot;https://realpython.com/pypi-publish-python-package/#poetry&quot;&gt;introduction to Poetry&lt;/a&gt; and can help you get started.&lt;/p&gt;
&lt;h2 id=&quot;conclusion-what-is-pip&quot;&gt;Conclusion: What Is &lt;code&gt;pip&lt;/code&gt;?&lt;/h2&gt;
&lt;p&gt;This tutorial answered the question, what is pip? You&amp;rsquo;ve seen that &lt;code&gt;pip&lt;/code&gt; is a package manager for Python, used by many projects to manage dependencies. It&amp;rsquo;s included with the Python installer, which makes it an essential tool for all Pythonistas to know how to use. &lt;/p&gt;
&lt;p&gt;Python provides an extensive standard library suitable for developing all sorts of applications, but the active Python community provides an even larger set of tools and libraries that speed up Python application development. &lt;/p&gt;
&lt;p&gt;These tools and libraries are published to the &lt;a href=&quot;https://pypi.org/&quot;&gt;Python Package Index&lt;/a&gt; (PyPI), and &lt;code&gt;pip&lt;/code&gt; allows developers to install them in their application environments.&lt;/p&gt;
&lt;p&gt;In this tutorial, you&amp;rsquo;ve learned about:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Installing new packages using &lt;code&gt;pip&lt;/code&gt; in the command line and with requirement files&lt;/li&gt;
&lt;li&gt;Managing dependencies, separating development and production requirements, and creating a locked requirements file&lt;/li&gt;
&lt;li&gt;Finding packages through &lt;code&gt;pip&lt;/code&gt; and PyPI&lt;/li&gt;
&lt;li&gt;Evaluating package dependencies before uninstalling a package and how &lt;code&gt;pip&lt;/code&gt; uninstalls packages&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In addition, you&amp;rsquo;ve learned about the importance of keeping dependencies up to date and alternatives to &lt;code&gt;pip&lt;/code&gt; that can help you manage those dependencies.&lt;/p&gt;
&lt;p&gt;Feel free to reach out in the comments section below with any questions you might have, and you can always get more information at the &lt;a href=&quot;https://pip.pypa.io/en/stable/&quot;&gt;&lt;code&gt;pip&lt;/code&gt; documentation page&lt;/a&gt;.&lt;/p&gt;
        &lt;hr /&gt;
        &lt;p&gt;&lt;em&gt;[ Improve Your Python With 🐍 Python Tricks 💌 – Get a short &amp;amp; sweet Python Trick delivered to your inbox every couple of days. &lt;a href=&quot;https://realpython.com/python-tricks/?utm_source=realpython&amp;amp;utm_medium=rss&amp;amp;utm_campaign=footer&quot;&gt;&amp;gt;&amp;gt; Click here to learn more and see examples&lt;/a&gt; ]&lt;/em&gt;&lt;/p&gt;
      </content>
    </entry>
  
    <entry>
      <title>Idiomatic Pandas: Tricks &amp; Features You May Not Know</title>
      <id>https://realpython.com/courses/idiomatic-pandas-tricks-features-you-may-not-know/</id>
      <link href="https://realpython.com/courses/idiomatic-pandas-tricks-features-you-may-not-know/"/>
      <updated>2019-04-02T14:00:00+00:00</updated>
      <summary>In this course you&#39;ll see how to use some lesser-used but idiomatic Pandas capabilities that lend your code better readability, versatility, and speed.</summary>
      <content type="html">
        &lt;p&gt;Pandas is a foundational library for analytics, data processing, and data science. It&amp;rsquo;s a huge project with tons of optionality and depth.&lt;/p&gt;
&lt;p&gt;In this course you&amp;rsquo;ll see how to use some lesser-used but idiomatic Pandas capabilities that lend your code better readability, versatility, and speed.&lt;/p&gt;
        &lt;hr /&gt;
        &lt;p&gt;&lt;em&gt;[ Improve Your Python With 🐍 Python Tricks 💌 – Get a short &amp;amp; sweet Python Trick delivered to your inbox every couple of days. &lt;a href=&quot;https://realpython.com/python-tricks/?utm_source=realpython&amp;amp;utm_medium=rss&amp;amp;utm_campaign=footer&quot;&gt;&amp;gt;&amp;gt; Click here to learn more and see examples&lt;/a&gt; ]&lt;/em&gt;&lt;/p&gt;
      </content>
    </entry>
  
    <entry>
      <title>Get Started With Django Part 1: Build a Portfolio App</title>
      <id>https://realpython.com/get-started-with-django-1/</id>
      <link href="https://realpython.com/get-started-with-django-1/"/>
      <updated>2019-04-01T14:00:00+00:00</updated>
      <summary>In this step-by-step tutorial, you&#39;ll learn the basics of creating powerful web applications with Django, a Python web framework. You&#39;ll build a portfolio application to showcase your web development projects, complete with a fully functioning blog.</summary>
      <content type="html">
        &lt;p&gt;Django is a fully featured Python web framework that can be used to build complex web applications. In this tutorial, you&amp;rsquo;ll jump in and learn &lt;a href=&quot;https://realpython.com/tutorials/django/&quot;&gt;Django&lt;/a&gt; by example. You&amp;rsquo;ll follow the steps to create a fully functioning web application and, along the way, learn some of the most important features of the framework and how they work together.&lt;/p&gt;
&lt;p&gt;In later posts in this series, you&amp;rsquo;ll see how to build more complex websites using even more of Django&amp;rsquo;s features than you&amp;rsquo;ll cover in this tutorial.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;By the end of this tutorial, you will be able to:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Understand what Django is and why it&amp;rsquo;s a great web framework&lt;/li&gt;
&lt;li&gt;Understand the architecture of a Django site and how it compares with other frameworks&lt;/li&gt;
&lt;li&gt;Set up a new Django project and app&lt;/li&gt;
&lt;li&gt;Build a Personal Portfolio Website with Django&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;alert alert-warning&quot; role=&quot;alert&quot;&gt;&lt;p&gt;&lt;strong&gt;Free Bonus:&lt;/strong&gt; &lt;a href=&quot;#&quot; class=&quot;alert-link&quot; data-toggle=&quot;modal&quot; data-target=&quot;#modal-django-resources-learing-guide&quot; data-focus=&quot;false&quot;&gt;Click here to get access to a free Django Learning Resources Guide (PDF)&lt;/a&gt; that shows you tips and tricks as well as common pitfalls to avoid when building Python + Django web applications.&lt;/p&gt;&lt;/div&gt;

&lt;h2 id=&quot;why-you-should-learn-django&quot;&gt;Why You Should Learn Django&lt;/h2&gt;
&lt;p&gt;There are endless web development frameworks out there, so why should you learn Django over any of the others? First of all, it&amp;rsquo;s written in Python, one of the most readable and beginner-friendly programming languages out there.&lt;/p&gt;
&lt;div class=&quot;alert alert-primary&quot; role=&quot;alert&quot;&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; This tutorial assumes an intermediate knowledge of the Python language. If you&amp;rsquo;re new to programming with Python, check out some of our &lt;a href=&quot;https://realpython.com/tutorials/basics/&quot;&gt;beginner tutorials&lt;/a&gt; or the &lt;a href=&quot;https://realpython.com/products/real-python-course/&quot;&gt;introductory course&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;The second reason you should learn Django is the scope of its features. If you need to build a website, you don&amp;rsquo;t need to rely on any external libraries or packages if you choose Django. This means that you don&amp;rsquo;t need to learn how to use anything else, and the syntax is seamless as you&amp;rsquo;re using only one framework.&lt;/p&gt;
&lt;p&gt;There&amp;rsquo;s also the added benefit that you don&amp;rsquo;t need to worry that updating one library or framework will render others that you&amp;rsquo;ve installed useless.&lt;/p&gt;
&lt;p&gt;If you do find yourself needing to add extra features, there are a range of external libraries that you can use to enhance your site.&lt;/p&gt;
&lt;p&gt;One of the great things about the Django framework is its &lt;a href=&quot;https://www.djangoproject.com/&quot;&gt;in-depth documentation&lt;/a&gt;. It has detailed documentation on every aspect of Django and also has great examples and even a tutorial to get you started.&lt;/p&gt;
&lt;p&gt;There&amp;rsquo;s also a fantastic community of Django developers, so if you get stuck there&amp;rsquo;s almost always a way forward by either checking the docs or &lt;a href=&quot;https://stackoverflow.com/questions/tagged/django&quot;&gt;asking the community&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Django is a high-level web application framework with loads of features. It&amp;rsquo;s great for anyone new to web development due to its fantastic documentation, and particularly if you&amp;rsquo;re also familiar with Python.&lt;/p&gt;
&lt;h2 id=&quot;the-structure-of-a-django-website&quot;&gt;The Structure of a Django Website&lt;/h2&gt;
&lt;p&gt;A Django website consists of a single &lt;strong&gt;project&lt;/strong&gt; that is split into separate &lt;strong&gt;apps&lt;/strong&gt;. The idea is that each app handles a self-contained function that the site needs to perform. As an example, imagine an application like Instagram. There are several different functions that need to be performed:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;User management&lt;/strong&gt;: Login, logout, register, and so on&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The image feed&lt;/strong&gt;: Uploading, editing, and displaying images&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Private messaging&lt;/strong&gt;: Private messages between users and notifications&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These are each separate pieces of functionality, so if this were a Django site, then each piece of functionality should be a different Django app inside a single Django project.&lt;/p&gt;
&lt;p&gt;The Django project holds some configurations that apply to the project as a whole, such as project settings, URLs, shared templates and static files. Each application can have its own database and has its own functions to control how the data is displayed to the user in HTML templates.&lt;/p&gt;
&lt;p&gt;Each application also has its own URLs as well as its own HTML templates and static files, such as JavaScript and CSS.&lt;/p&gt;
&lt;p&gt;Django apps are structured so that there is a separation of logic. It supports the Model-View-Controller Pattern, which is the architecture on which most web frameworks are built. The basic principle is that in each application there are three separate files that handle the three main pieces of logic separately:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Model&lt;/strong&gt; defines the data structure. This is usually a database and is the base layer to an application.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;View&lt;/strong&gt; displays some or all of the data to the user with HTML and CSS.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Controller&lt;/strong&gt; handles how the database and the view interact.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you want to learn more about the MVC pattern, then check out &lt;a href=&quot;https://realpython.com/the-model-view-controller-mvc-paradigm-summarized-with-legos/&quot;&gt;Model-View-Controller (MVC) Explained – With Legos&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In Django, the architecture is slightly different. Although based upon the MVC pattern, Django handles the controller part itself. There&amp;rsquo;s no need to define how the database and views interact. It&amp;rsquo;s all done for you!&lt;/p&gt;
&lt;p&gt;The pattern Django utilizes is called the Model-View-Template (MVT) pattern. The view and template in the MVT pattern make up the view in the MVC pattern. All you need to do is add some URL configurations to map the views to, and Django handles the rest!&lt;/p&gt;
&lt;p&gt;A Django site starts off as a project and is built up with a number of applications that each handle separate functionality. Each app follows the Model-View-Template pattern. Now that you&amp;rsquo;re familiar with the structure of a Django site, let&amp;rsquo;s have a look at what you&amp;rsquo;re going to build!&lt;/p&gt;
&lt;h2 id=&quot;what-youre-going-to-build&quot;&gt;What You&amp;rsquo;re Going to Build&lt;/h2&gt;
&lt;p&gt;Before you get started with any web development project, it&amp;rsquo;s a good idea to come up with a plan of what you&amp;rsquo;re going to build. In this tutorial, we are going to build an application with the following features:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;A fully functioning blog&lt;/strong&gt;: If you&amp;rsquo;re looking to demonstrate your coding ability, a blog is a great way to do that. In this application, you will be able to create, update, and delete blog posts. Posts will have categories that can be used to sort them. Finally, users will be able to leave comments on posts.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;A portfolio of your work&lt;/strong&gt;: You can showcase previous &lt;a href=&quot;https://realpython.com/tutorials/web-dev/&quot;&gt;web development&lt;/a&gt; projects here. You&amp;rsquo;ll build a gallery style page with clickable links to projects that you&amp;rsquo;ve completed.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;alert alert-primary&quot; role=&quot;alert&quot;&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Before you get started, you can pull down the &lt;a href=&quot;https://github.com/realpython/materials/tree/master/rp-portfolio&quot;&gt;source code&lt;/a&gt; and follow along with the tutorial.&lt;/p&gt;
&lt;p&gt;If you prefer to follow along by writing the code yourself, don&amp;rsquo;t worry. I&amp;rsquo;ve referenced the relevant parts of the source code throughout so you can refer back to it.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;We won&amp;rsquo;t be using any external Python libraries in this tutorial. One of the great things about Django is that it has so many features that you don&amp;rsquo;t need to rely on external libraries. However, we will add &lt;a href=&quot;https://getbootstrap.com/&quot;&gt;Bootstrap 4&lt;/a&gt; styling in the templates.&lt;/p&gt;
&lt;p&gt;By building these two apps, you&amp;rsquo;ll learn the basics of Django models, view functions, forms, templates, and the Django admin page. With knowledge of these features, you&amp;rsquo;ll be able to go away and build loads more applications. You&amp;rsquo;ll also have the tools to learn even more and build sophisticated Django sites.&lt;/p&gt;
&lt;h2 id=&quot;hello-world&quot;&gt;Hello, World!&lt;/h2&gt;
&lt;p&gt;Now that you know the structure of a Django application, and what you are about to build, we&amp;rsquo;re going to go through the process of creating an application in Django. You&amp;rsquo;ll extend this later into your personal portfolio application.&lt;/p&gt;
&lt;h3 id=&quot;set-up-your-development-environment&quot;&gt;Set Up Your Development Environment&lt;/h3&gt;
&lt;p&gt;Whenever you are starting a new web development project, it&amp;rsquo;s a good idea to first set up your development environment. Create a new directory for your project to live in, and &lt;code&gt;cd&lt;/code&gt; into it:&lt;/p&gt;
&lt;div class=&quot;highlight sh&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; mkdir rp-portfolio
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; rp-portfolio
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Once your inside the main directory, it&amp;rsquo;s a good idea to create a &lt;a href=&quot;https://realpython.com/python-virtual-environments-a-primer/&quot;&gt;virtual environment&lt;/a&gt; to manage dependencies. There are many different ways to set up virtual environments, but here you&amp;rsquo;re going to use &lt;code&gt;venv&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight sh&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; python3 -m venv venv
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This command will create a folder &lt;code&gt;venv&lt;/code&gt; in your working directory. Inside this directory, you&amp;rsquo;ll find several files including a copy of the Python standard library. Later, when you install new dependencies, they will also be stored in this directory. Next, you need to activate the virtual environment by running the following command:&lt;/p&gt;
&lt;div class=&quot;highlight sh&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;source&lt;/span&gt; venv/bin/activate
&lt;/pre&gt;&lt;/div&gt;

&lt;div class=&quot;alert alert-primary&quot; role=&quot;alert&quot;&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; If you&amp;rsquo;re not using bash shell, you might need to use a &lt;a href=&quot;https://docs.python.org/3/library/venv.html#creating-virtual-environments&quot;&gt;different command&lt;/a&gt; to activate your virtual environment. For example, on windows you need this command:&lt;/p&gt;
&lt;div class=&quot;highlight doscon&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;C:\&amp;gt;&lt;/span&gt; venv\Scripts\activate.bat
&lt;/pre&gt;&lt;/div&gt;

&lt;/div&gt;
&lt;p&gt;You&amp;rsquo;ll know that your virtual environment has been activated, because your console prompt in the terminal will change. It should look something like this:&lt;/p&gt;
&lt;div class=&quot;highlight sh&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;(venv) $&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;div class=&quot;alert alert-primary&quot; role=&quot;alert&quot;&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Your virtual environment directory doesn&amp;rsquo;t have to be called &lt;code&gt;venv&lt;/code&gt;. If you want to create one under a different name, for example &lt;code&gt;my_venv&lt;/code&gt;, just replace with the second &lt;code&gt;venv&lt;/code&gt; with &lt;code&gt;my_venv&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Then, when activating your virtual environment, replace &lt;code&gt;venv&lt;/code&gt; with &lt;code&gt;my_venv&lt;/code&gt; again. The prompt will also now be prefixed with &lt;code&gt;(my_venv)&lt;/code&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;Now that you&amp;rsquo;ve created a virtual environment, it&amp;rsquo;s time to install Django. You can do this using &lt;code&gt;pip&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight sh&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;(venv) $&lt;/span&gt; pip install Django
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Once you&amp;rsquo;ve set up the virtual environment and installed Django, you can now dive in to creating the application.&lt;/p&gt;
&lt;h3 id=&quot;create-a-django-project&quot;&gt;Create a Django Project&lt;/h3&gt;
&lt;p&gt;As you saw in the previous section, a Django web application is made up of a project and its constituent apps. Making sure you&amp;rsquo;re in the &lt;code&gt;rp_portfolio&lt;/code&gt; directory, and you&amp;rsquo;ve activated your virtual environment, run the following command to create the project:&lt;/p&gt;
&lt;div class=&quot;highlight sh&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; django-admin startproject personal_portfolio
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This will create a new directory &lt;code&gt;personal_portfolio&lt;/code&gt;. If you &lt;code&gt;cd&lt;/code&gt; into this new directory you&amp;rsquo;ll see &lt;em&gt;another&lt;/em&gt; directory called &lt;code&gt;personal_portfolio&lt;/code&gt; and a file called &lt;code&gt;manage.py&lt;/code&gt;. Your directory structure should look something like this:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;rp-portfolio/
│
├── personal_portfolio/
│   ├── personal_portfolio/
│   │   ├── __init__.py
│   │   ├── settings.py
│   │   ├── urls.py
│   │   └── wsgi.py
│   │
│   └── manage.py
│
└── venv/
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Most of the work you do will be in that first &lt;code&gt;personal_portfolio&lt;/code&gt; directory. To save having to &lt;code&gt;cd&lt;/code&gt; through several directories each time you come to work on your project, it can be helpful to reorder this slightly by moving all the files up a directory. While you&amp;rsquo;re in the &lt;code&gt;rp-portfolio&lt;/code&gt; directory, run the following commands:&lt;/p&gt;
&lt;div class=&quot;highlight sh&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; mv personal_portfolio/manage.py ./
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; mv personal_portfolio/personal_portfolio/* personal_portfolio
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; rm -r personal_portfolio/personal_portfolio/
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You should end up with something like this:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;rp-portfolio/
│
├── personal_portfolio/
│   ├── __init__.py
│   ├── settings.py
│   ├── urls.py
│   └── wsgi.py
│
├── venv/
│
└── manage.py
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Once your file structure is set up, you can now start the server and check that your set up was successful. In the console, run the following command:&lt;/p&gt;
&lt;div class=&quot;highlight sh&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; python manage.py runserver
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Then, in your browser go to &lt;code&gt;localhost:8000&lt;/code&gt;, and you should see the following:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://files.realpython.com/media/Screenshot_2018-12-09_at_17.58.16.20be0c5d3f1e.png&quot; target=&quot;_blank&quot;&gt;&lt;img class=&quot;img-fluid mx-auto d-block &quot; src=&quot;https://files.realpython.com/media/Screenshot_2018-12-09_at_17.58.16.20be0c5d3f1e.png&quot; width=&quot;2332&quot; height=&quot;1600&quot; srcset=&quot;https://robocrop.realpython.net/?url=https%3A//files.realpython.com/media/Screenshot_2018-12-09_at_17.58.16.20be0c5d3f1e.png&amp;amp;w=583&amp;amp;sig=e1f6932faf00b971880a614f48267fb9259b9948 583w, https://robocrop.realpython.net/?url=https%3A//files.realpython.com/media/Screenshot_2018-12-09_at_17.58.16.20be0c5d3f1e.png&amp;amp;w=1166&amp;amp;sig=4ffc2fd1351ae277e120dc5f29821f4cd544a11a 1166w, https://files.realpython.com/media/Screenshot_2018-12-09_at_17.58.16.20be0c5d3f1e.png 2332w&quot; sizes=&quot;75vw&quot; alt=&quot;Initial view of Django site&quot;/&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Congratulations, you&amp;rsquo;ve created a Django site! The source code for this part of the tutorial can be found on &lt;a href=&quot;https://github.com/realpython/materials/tree/a639f1c2f85032334fbb4dca88f3e8dc88397f6d/rp-portfolio&quot;&gt;GitHub&lt;/a&gt;. The next step is to create apps so that you can add views and functionality to your site.&lt;/p&gt;
&lt;h3 id=&quot;create-a-django-application&quot;&gt;Create a Django Application&lt;/h3&gt;
&lt;p&gt;For this part of the tutorial, we&amp;rsquo;ll create an app called &lt;code&gt;hello_world&lt;/code&gt;, which you&amp;rsquo;ll subsequently delete as its not necessary for our personal portfolio site.&lt;/p&gt;
&lt;p&gt;To create the app, run the following command:&lt;/p&gt;
&lt;div class=&quot;highlight sh&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; python manage.py startapp hello_world
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This will create another directory called &lt;code&gt;hello_world&lt;/code&gt; with several files:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;__init__.py&lt;/code&gt;&lt;/strong&gt; tells Python to treat the directory as a Python package.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;admin.py&lt;/code&gt;&lt;/strong&gt; contains settings for the Django admin pages.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;apps.py&lt;/code&gt;&lt;/strong&gt; contains settings for the application configuration.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;models.py&lt;/code&gt;&lt;/strong&gt; contains a series of classes that Django&amp;rsquo;s ORM converts to database tables.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;tests.py&lt;/code&gt;&lt;/strong&gt; contains test classes.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;views.py&lt;/code&gt;&lt;/strong&gt; contains functions and classes that handle what data is displayed in the HTML templates.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Once you&amp;rsquo;ve created the app, you need to install it in your project. In &lt;code&gt;rp-portfolio/settings.py&lt;/code&gt;, add the following line of code under &lt;code&gt;INSTALLED_APPS&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight python&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;INSTALLED_APPS&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;s1&quot;&gt;&amp;#39;django.contrib.admin&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s1&quot;&gt;&amp;#39;django.contrib.auth&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s1&quot;&gt;&amp;#39;django.contrib.contenttypes&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s1&quot;&gt;&amp;#39;django.contrib.sessions&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s1&quot;&gt;&amp;#39;django.contrib.messages&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s1&quot;&gt;&amp;#39;django.contrib.staticfiles&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;hll&quot;&gt;    &lt;span class=&quot;s1&quot;&gt;&amp;#39;hello_world&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;That line of code means that your project now knows that the app you just created exists. The next step is to create a view so that you can display something to a user.&lt;/p&gt;
&lt;h3 id=&quot;create-a-view&quot;&gt;Create a View&lt;/h3&gt;
&lt;p&gt;Views in Django are a collection of functions or classes inside the &lt;code&gt;views.py&lt;/code&gt; file in your app directory. Each function or class handles the logic that gets processed each time a different URL is visited.&lt;/p&gt;
&lt;p&gt;Navigate to the &lt;code&gt;views.py&lt;/code&gt; file in the &lt;code&gt;hello_world&lt;/code&gt; directory. There&amp;rsquo;s already a line of code in there that imports &lt;code&gt;render()&lt;/code&gt;. Add the following code:&lt;/p&gt;
&lt;div class=&quot;highlight python&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;django.shortcuts&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;render&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;hello_world&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
&lt;span class=&quot;hll&quot;&gt;    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;hello_world.html&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{})&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In this piece of code, you&amp;rsquo;ve defined a &lt;strong&gt;view function&lt;/strong&gt; called &lt;code&gt;hello_world()&lt;/code&gt;. When this function is called, it will render an HTML file called &lt;code&gt;hello_world.html&lt;/code&gt;. That file doesn&amp;rsquo;t exist yet, but we&amp;rsquo;ll create it soon.&lt;/p&gt;
&lt;p&gt;The view function takes one argument, &lt;code&gt;request&lt;/code&gt;. This object is an &lt;code&gt;HttpRequestObject&lt;/code&gt; that is created whenever a page is loaded. It contains information about the request, such as the method, which can take several values including &lt;code&gt;GET&lt;/code&gt; and &lt;code&gt;POST&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Now that you&amp;rsquo;ve created the view function, you need to create the HTML template to display to the user. &lt;code&gt;render()&lt;/code&gt; looks for HTML templates inside a directory called &lt;code&gt;templates&lt;/code&gt; inside your app directory. Create that directory and subsequently a file named &lt;code&gt;hello_world.html&lt;/code&gt; inside it:&lt;/p&gt;
&lt;div class=&quot;highlight sh&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; mkdir hello_world/templates/
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; touch hello_world/templates/hello_world.html
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Add the following lines of HTML to your file:&lt;/p&gt;
&lt;div class=&quot;highlight htmldjango&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;h1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;Hello, World!&lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;h1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You&amp;rsquo;ve now created a function to handle your views and templates to display to the user. The final step is to hook up your URLs so that you can visit the page you&amp;rsquo;ve just created. Your project has a module called &lt;code&gt;urls.py&lt;/code&gt; in which you need to include a URL configuration for the &lt;code&gt;hello_world&lt;/code&gt; app. Inside &lt;code&gt;personal_portfolio/urls.py&lt;/code&gt;, add the following:&lt;/p&gt;
&lt;div class=&quot;highlight python&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;django.contrib&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;admin&lt;/span&gt;
&lt;span class=&quot;hll&quot;&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;django.urls&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;include&lt;/span&gt;
&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;urlpatterns&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;admin/&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;admin&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;site&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;urls&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
&lt;span class=&quot;hll&quot;&gt;    &lt;span class=&quot;n&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;include&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;hello_world.urls&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)),&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This looks for a module called &lt;code&gt;urls.py&lt;/code&gt; inside the &lt;code&gt;hello_world&lt;/code&gt; application and registers any URLs defined there. Whenever you visit the root path of your URL (&lt;code&gt;localhost:8000&lt;/code&gt;), the &lt;code&gt;hello_world&lt;/code&gt; application&amp;rsquo;s URLs will be registered. The &lt;code&gt;hello_world.urls&lt;/code&gt; module doesn&amp;rsquo;t exist yet, so you&amp;rsquo;ll need to create it:&lt;/p&gt;
&lt;div class=&quot;highlight sh&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; touch hello_world/urls.py
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Inside this module, we need to import the path object as well as our app&amp;rsquo;s &lt;code&gt;views&lt;/code&gt; module. Then we want to create a list of URL patterns that correspond to the various view functions. At the moment, we have only created one view function, so we need only create one URL:&lt;/p&gt;
&lt;div class=&quot;highlight python&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;django.urls&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;path&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;hello_world&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;views&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;urlpatterns&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;views&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hello_world&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;hello_world&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now, when you restart the server and visit &lt;code&gt;localhost:8000&lt;/code&gt;, you should be able to see the HTML template you created:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://files.realpython.com/media/Screenshot_2018-12-09_at_17.57.22.f3c9ea711bd4.png&quot; target=&quot;_blank&quot;&gt;&lt;img class=&quot;img-fluid mx-auto d-block &quot; src=&quot;https://files.realpython.com/media/Screenshot_2018-12-09_at_17.57.22.f3c9ea711bd4.png&quot; width=&quot;2332&quot; height=&quot;1600&quot; srcset=&quot;https://robocrop.realpython.net/?url=https%3A//files.realpython.com/media/Screenshot_2018-12-09_at_17.57.22.f3c9ea711bd4.png&amp;amp;w=583&amp;amp;sig=ce7e968bfed6b86f9e943ed3eda22be6390cb04b 583w, https://robocrop.realpython.net/?url=https%3A//files.realpython.com/media/Screenshot_2018-12-09_at_17.57.22.f3c9ea711bd4.png&amp;amp;w=1166&amp;amp;sig=f49cdefd0aa57477917d8d7afb68a6d8d9e4dda7 1166w, https://files.realpython.com/media/Screenshot_2018-12-09_at_17.57.22.f3c9ea711bd4.png 2332w&quot; sizes=&quot;75vw&quot; alt=&quot;Hello, World! view of Django site&quot;/&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Congratulations, again! You&amp;rsquo;ve created your first Django app and hooked it up to your project. Don&amp;rsquo;t forget to check out the &lt;a href=&quot;https://github.com/realpython/materials/tree/754bf43a150b818f73e6508fd937eefee997cc6c/rp-portfolio&quot;&gt;source code&lt;/a&gt; for this section and the previous one. The only problem now is that it doesn&amp;rsquo;t look very nice. In the next section, we&amp;rsquo;re going to add bootstrap styles to your project to make it prettier!&lt;/p&gt;
&lt;h3 id=&quot;add-bootstrap-to-your-app&quot;&gt;Add Bootstrap to Your App&lt;/h3&gt;
&lt;p&gt;If you don&amp;rsquo;t add any styling, then the app you create isn&amp;rsquo;t going to look too nice. Instead of going into CSS styling with this tutorial, we&amp;rsquo;ll just cover how to add bootstrap styles to your project. This will allow us to improve the look of the site without too much effort.&lt;/p&gt;
&lt;p&gt;Before we get started with the Bootstrap styles, we&amp;rsquo;ll create a base template that we can import to each subsequent view. This template is where we&amp;rsquo;ll subsequently add the Bootstrap style imports.&lt;/p&gt;
&lt;p&gt;Create another directory called &lt;code&gt;templates&lt;/code&gt;, this time inside &lt;code&gt;personal_portfolio&lt;/code&gt;, and a file called &lt;code&gt;base.html&lt;/code&gt;, inside the new directory:&lt;/p&gt;
&lt;div class=&quot;highlight sh&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; mkdir personal_portfolio/templates/
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; touch personal_portfolio/templates/base.html
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;We create this additional templates directory to store HTML templates that will be used in every Django app in the project. As you saw previously, each Django project can consist of multiple apps that handle separated logic, and each app contains its own &lt;code&gt;templates&lt;/code&gt; directory to store HTML templates related to the application.&lt;/p&gt;
&lt;p&gt;This application structure works well for the back end logic, but we want our entire site to look consistent on the front end. Instead of having to import Bootstrap styles into every app, we can create a template or set of templates that are shared by all the apps. As long as Django knows to look for templates in this new, shared directory it can save a lot of repeated styles.&lt;/p&gt;
&lt;p&gt;Inside this new file (&lt;code&gt;personal_portfolio/templates/base.html&lt;/code&gt;), add the following lines of code:&lt;/p&gt;
&lt;div class=&quot;highlight htmldjango&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;block&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;page_content&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;endblock&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now, in &lt;code&gt;hello_world/templates/hello_world.html&lt;/code&gt;, we can extend this base template:&lt;/p&gt;
&lt;div class=&quot;highlight htmldjango&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;hll&quot;&gt;&lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;base.html&amp;quot;&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;
&lt;/span&gt;
&lt;span class=&quot;hll&quot;&gt;&lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;block&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;page_content&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;h1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;Hello, World!&lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;h1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;hll&quot;&gt;&lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;endblock&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;What happens here is that any HTML inside the &lt;code&gt;page_content&lt;/code&gt; block gets added inside the same block in &lt;code&gt;base.html&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;To install Bootstrap in your app, you&amp;rsquo;ll use the &lt;a href=&quot;https://getbootstrap.com/docs/4.1/getting-started/introduction/#quick-start&quot;&gt;Bootstrap CDN&lt;/a&gt;. This is a really simple way to install Bootstrap that just involves adding a few lines of code to &lt;code&gt;base.html&lt;/code&gt;. Check out the &lt;a href=&quot;https://github.com/realpython/materials/blob/1ea78b8bb71e685c476d6fd98e829b6ad0a42123/rp-portfolio/personal_portfolio/templates/base.html&quot;&gt;source code&lt;/a&gt; to see how to add the CDN links to your project.&lt;/p&gt;
&lt;p&gt;All future templates that we create will extend &lt;code&gt;base.html&lt;/code&gt; so that we can include Bootstrap styling on every page without having to import the styles again.&lt;/p&gt;
&lt;p&gt;Before we can see our new styled application, we need to tell our Django project that &lt;code&gt;base.html&lt;/code&gt; exists. The default settings register &lt;code&gt;template&lt;/code&gt; directories in each app, but not in the project directory itself. In &lt;code&gt;personal_portfolio/settings.py&lt;/code&gt;, update &lt;code&gt;TEMPLATES&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight python&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TEMPLATES&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;s2&quot;&gt;&amp;quot;BACKEND&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;django.template.backends.django.DjangoTemplates&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;hll&quot;&gt;        &lt;span class=&quot;s2&quot;&gt;&amp;quot;DIRS&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;personal_portfolio/templates/&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
&lt;/span&gt;        &lt;span class=&quot;s2&quot;&gt;&amp;quot;APP_DIRS&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s2&quot;&gt;&amp;quot;OPTIONS&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;s2&quot;&gt;&amp;quot;context_processors&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
                &lt;span class=&quot;s2&quot;&gt;&amp;quot;django.template.context_processors.debug&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                &lt;span class=&quot;s2&quot;&gt;&amp;quot;django.template.context_processors.request&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                &lt;span class=&quot;s2&quot;&gt;&amp;quot;django.contrib.auth.context_processors.auth&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                &lt;span class=&quot;s2&quot;&gt;&amp;quot;django.contrib.messages.context_processors.messages&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now, when you visit &lt;code&gt;localhost:8000&lt;/code&gt;, you should see that the page has been formatted with slightly different styling:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://files.realpython.com/media/Screenshot_2018-12-09_at_19.46.23.cd4783f33899.png&quot; target=&quot;_blank&quot;&gt;&lt;img class=&quot;img-fluid mx-auto d-block &quot; src=&quot;https://files.realpython.com/media/Screenshot_2018-12-09_at_19.46.23.cd4783f33899.png&quot; width=&quot;2332&quot; height=&quot;1600&quot; srcset=&quot;https://robocrop.realpython.net/?url=https%3A//files.realpython.com/media/Screenshot_2018-12-09_at_19.46.23.cd4783f33899.png&amp;amp;w=583&amp;amp;sig=04f4551691b0ef74a52f0b8961c9d178fbaab226 583w, https://robocrop.realpython.net/?url=https%3A//files.realpython.com/media/Screenshot_2018-12-09_at_19.46.23.cd4783f33899.png&amp;amp;w=1166&amp;amp;sig=8a6be1d612ccc4a6fac967f15d65546c1dd56177 1166w, https://files.realpython.com/media/Screenshot_2018-12-09_at_19.46.23.cd4783f33899.png 2332w&quot; sizes=&quot;75vw&quot; alt=&quot;Hello, World! view of Django site with Bootstrap styles&quot;/&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Whenever you want create templates or import scripts that you intend to use in all your Django apps inside a project, you can add them to this project-level directory and extend them inside your app templates.&lt;/p&gt;
&lt;p&gt;Adding templates is the last stage to building your &lt;em&gt;Hello, World!&lt;/em&gt; Django site. You learned how the Django templating engine works and how to create project-level templates that can be shared by all the apps inside your Django project.&lt;/p&gt;
&lt;p&gt;In this section, you learned how to create a simple &lt;em&gt;Hello, World!&lt;/em&gt; Django site by creating a project with a single app. In the next section, you&amp;rsquo;ll create another application to showcase web development projects, and you&amp;rsquo;ll learn all about models in Django!&lt;/p&gt;
&lt;p&gt;The source code for this section can be found on &lt;a href=&quot;https://github.com/realpython/materials/tree/1ea78b8bb71e685c476d6fd98e829b6ad0a42123/rp-portfolio/hello_world&quot;&gt;GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;showcase-your-projects&quot;&gt;Showcase Your Projects&lt;/h2&gt;
&lt;p&gt;Any web developer looking to create a portfolio needs a way to show off projects they have worked on. That&amp;rsquo;s what you&amp;rsquo;ll be building now. You&amp;rsquo;ll create another Django app called &lt;code&gt;projects&lt;/code&gt; that will hold a series of sample projects that will be displayed to the user. Users can click on projects and see more information about your work.&lt;/p&gt;
&lt;p&gt;Before we build the &lt;code&gt;projects&lt;/code&gt; app, let&amp;rsquo;s first delete the &lt;code&gt;hello_world&lt;/code&gt; application. All you need to do is delete the &lt;code&gt;hello_world&lt;/code&gt; directory and remove the line &lt;code&gt;&quot;hello_world&quot;,&lt;/code&gt; from &lt;code&gt;INSTALLED_APPS&lt;/code&gt; in &lt;code&gt;settings.py&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight python&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;INSTALLED_APPS&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;s1&quot;&gt;&amp;#39;django.contrib.admin&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s1&quot;&gt;&amp;#39;django.contrib.auth&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s1&quot;&gt;&amp;#39;django.contrib.contenttypes&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s1&quot;&gt;&amp;#39;django.contrib.sessions&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s1&quot;&gt;&amp;#39;django.contrib.messages&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s1&quot;&gt;&amp;#39;django.contrib.staticfiles&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;hll&quot;&gt;    &lt;span class=&quot;s1&quot;&gt;&amp;#39;hello_world&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# Delete this line&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Finally, you need to remove the URL path created in &lt;code&gt;personal_portfolio/urls.py&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight python&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;django.contrib&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;admin&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;django.urls&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;include&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;urlpatterns&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;admin/&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;admin&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;site&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;urls&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
&lt;span class=&quot;hll&quot;&gt;    &lt;span class=&quot;n&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;include&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;hello_world.urls&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)),&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# Delete this line&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now that you&amp;rsquo;ve removed the &lt;code&gt;hello_world&lt;/code&gt; app, we can create the &lt;code&gt;projects&lt;/code&gt; app. Making sure you&amp;rsquo;re in the &lt;code&gt;rp-portfolio&lt;/code&gt; directory, run the following command in your console:&lt;/p&gt;
&lt;div class=&quot;highlight sh&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; python manage.py startapp projects
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This will create a directory named &lt;code&gt;projects&lt;/code&gt;. The files created are the same as those created when we set up the &lt;code&gt;hello_world&lt;/code&gt; application. In order to hook up our app, we need to add it into &lt;code&gt;INSTALLED_APPS&lt;/code&gt; in &lt;code&gt;settings.py&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight python&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;INSTALLED_APPS&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;s1&quot;&gt;&amp;#39;django.contrib.admin&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s1&quot;&gt;&amp;#39;django.contrib.auth&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s1&quot;&gt;&amp;#39;django.contrib.contenttypes&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s1&quot;&gt;&amp;#39;django.contrib.sessions&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s1&quot;&gt;&amp;#39;django.contrib.messages&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s1&quot;&gt;&amp;#39;django.contrib.staticfiles&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;hll&quot;&gt;    &lt;span class=&quot;s1&quot;&gt;&amp;#39;projects&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Check out the &lt;a href=&quot;https://github.com/realpython/materials/tree/4de6ebd8baebec950357d4f479fcc0de962e6ae4/rp-portfolio&quot;&gt;source code&lt;/a&gt; for this section on GitHub. We&amp;rsquo;re not going to worry about URLs for this application just yet. Instead, we&amp;rsquo;re going to focus on building a &lt;code&gt;Project&lt;/code&gt; model.&lt;/p&gt;
&lt;h3 id=&quot;projects-app-models&quot;&gt;Projects App: Models&lt;/h3&gt;
&lt;p&gt;If you want to store data to display on a website, then you&amp;rsquo;ll need a database. Typically, if you want to create a database with tables and columns within those tables, you&amp;rsquo;ll need to use SQL to manage the database. But when you use Django, you don&amp;rsquo;t need to learn a new language because it has a built-in Object Relational Mapper (ORM).&lt;/p&gt;
&lt;p&gt;An ORM is a program that allows you to create classes that correspond to database tables. Class attributes correspond to columns, and instances of the classes correspond to rows in the database. So, instead of learning a whole new language to create our database and its tables, we can just write some Python classes.&lt;/p&gt;
&lt;p&gt;When you&amp;rsquo;re using an ORM, the classes you build that represent database tables are referred to as &lt;strong&gt;models&lt;/strong&gt;. In Django, they live in the &lt;code&gt;models.py&lt;/code&gt; module of each Django app.&lt;/p&gt;
&lt;p&gt;In your projects app, you&amp;rsquo;ll only need one table to store the different projects you&amp;rsquo;ll display to the user. That means you&amp;rsquo;ll only need to create one model in &lt;code&gt;models.py&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The model you&amp;rsquo;ll create will be called &lt;code&gt;Project&lt;/code&gt; and will have the following fields:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;title&lt;/code&gt;&lt;/strong&gt; will be a short string field to hold the name of your project.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;description&lt;/code&gt;&lt;/strong&gt; will be a larger string field to hold a longer piece of text.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;technology&lt;/code&gt;&lt;/strong&gt; will be a string field, but its contents will be limited to a select number of choices.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;image&lt;/code&gt;&lt;/strong&gt; will be an image field that holds the file path where the image is stored.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To create this model, we&amp;rsquo;ll create a new class in &lt;code&gt;models.py&lt;/code&gt; and add the following in our fields:&lt;/p&gt;
&lt;div class=&quot;highlight python&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;django.db&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;models&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Project&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;models&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;title&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;models&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CharField&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;max_length&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;description&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;models&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TextField&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;technology&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;models&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CharField&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;max_length&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;image&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;models&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;FilePathField&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;/img&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Django models come with many &lt;a href=&quot;https://docs.djangoproject.com/en/2.1/ref/models/fields/&quot;&gt;built-in model field types&lt;/a&gt;. We&amp;rsquo;ve only used three in this model. &lt;code&gt;CharField&lt;/code&gt; is used for short strings and specifies a maximum length.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;TextField&lt;/code&gt; is similar to &lt;code&gt;CharField&lt;/code&gt; but can be used for longer form text as it doesn&amp;rsquo;t have a maximum length limit. Finally, &lt;code&gt;FilePathField&lt;/code&gt; also holds a string but must point to a file path name.&lt;/p&gt;
&lt;p&gt;Now that we&amp;rsquo;ve created our &lt;code&gt;Project&lt;/code&gt; class, we need Django to create the database. By default, the Django ORM creates databases in SQLite, but you can use other databases that use the SQL language, such as PostgreSQL or MySQL, with the Django ORM.&lt;/p&gt;
&lt;p&gt;To start the process of creating our database, we need to create a &lt;strong&gt;migration&lt;/strong&gt;. A migration is a file containing a &lt;code&gt;Migration&lt;/code&gt; class with rules that tell Django what changes need to be made to the database. To create the migration, type the following command in the console, making sure you&amp;rsquo;re in the &lt;code&gt;rp-portfolio&lt;/code&gt; directory:&lt;/p&gt;
&lt;div class=&quot;highlight sh&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; python manage.py makemigrations projects
&lt;span class=&quot;go&quot;&gt;Migrations for &amp;#39;projects&amp;#39;:&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  projects/migrations/0001_initial.py&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;    - Create model Project&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You should see that a file &lt;code&gt;projects/migrations/0001_initial.py&lt;/code&gt; has been created in the projects app. Check out that file in the &lt;a href=&quot;https://github.com/realpython/materials/blob/0091ee5421f8107e8629f1f22687ff224850b889/rp-portfolio/projects/migrations/0001_initial.py&quot;&gt;source code&lt;/a&gt; to make sure your migration is correct.&lt;/p&gt;
&lt;p&gt;Now that you&amp;rsquo;ve create a migration file, you need to apply the migrations set out in the migrations file and create your database using the &lt;code&gt;migrate&lt;/code&gt; command:&lt;/p&gt;
&lt;div class=&quot;highlight sh&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; python manage.py migrate projects
&lt;span class=&quot;go&quot;&gt;Operations to perform:&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  Apply all migrations: projects&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Running migrations:&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  Applying projects.0001_initial... OK&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;div class=&quot;alert alert-primary&quot; role=&quot;alert&quot;&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; When running both the &lt;code&gt;makemigrations&lt;/code&gt; and &lt;code&gt;migrate&lt;/code&gt; commands, we added &lt;code&gt;projects&lt;/code&gt; to our command. This tells Django to only look at models and migrations in the &lt;code&gt;projects&lt;/code&gt; app. Django comes with several models already created.&lt;/p&gt;
&lt;p&gt;If you run &lt;code&gt;makemigrations&lt;/code&gt; and &lt;code&gt;migrate&lt;/code&gt; without the &lt;code&gt;projects&lt;/code&gt; flag, then all migrations for all the default models in your Django projects will be created and applied. This is not a problem, but for the purposes of this section, they are not needed.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;You should also see that a file called &lt;code&gt;db.sqlite3&lt;/code&gt; has been created in the root of your project. Now your database is set up and ready to go. You can now create rows in your table that are the various projects you want to show on your portfolio site.&lt;/p&gt;
&lt;p&gt;To create instances of our &lt;code&gt;Project&lt;/code&gt; class, we&amp;rsquo;re going to have to use the Django shell. The Django shell is similar to the Python shell but allows you to access the database and create entries. To access the Django shell, we use another Django management command:&lt;/p&gt;
&lt;div class=&quot;highlight sh&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; python manage.py shell
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Once you&amp;rsquo;ve accessed the shell, you&amp;rsquo;ll notice that the command prompt will change from &lt;code&gt;$&lt;/code&gt; to &lt;code&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/code&gt;. You can then import your models:&lt;/p&gt;
&lt;div class=&quot;highlight python pycon&quot;&gt;&lt;span class=&quot;repl-toggle&quot; title=&quot;Toggle REPL prompts and output&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;projects.models&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Project&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;We&amp;rsquo;re first going to create a new project with the following attributes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;name&lt;/code&gt;:&lt;/strong&gt; &lt;code&gt;My First Project&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;description&lt;/code&gt;:&lt;/strong&gt; &lt;code&gt;A web development project.&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;technology&lt;/code&gt;:&lt;/strong&gt; &lt;code&gt;Django&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;image&lt;/code&gt;:&lt;/strong&gt; &lt;code&gt;img/project1.png&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To do this, we create an instance of the Project class in the Django shell:&lt;/p&gt;
&lt;div class=&quot;highlight python pycon&quot;&gt;&lt;span class=&quot;repl-toggle&quot; title=&quot;Toggle REPL prompts and output&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;p1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Project&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;... &lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;My First Project&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;... &lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;description&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;A web development project.&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;... &lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;technology&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;Django&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;... &lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;img/project1.png&amp;#39;&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;... &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;p1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;save&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This creates a new entry in your projects table and saves it to the database. Now you have created a project that you can display on your portfolio site.&lt;/p&gt;
&lt;p&gt;The final step in this section is to create two more sample projects:&lt;/p&gt;
&lt;div class=&quot;highlight python pycon&quot;&gt;&lt;span class=&quot;repl-toggle&quot; title=&quot;Toggle REPL prompts and output&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;p2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Project&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;... &lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;My Second Project&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;... &lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;description&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;Another web development project.&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;... &lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;technology&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;Flask&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;... &lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;img/project2.png&amp;#39;&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;... &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;p2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;save&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;p3&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Project&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;... &lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;My Third Project&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;... &lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;description&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;A final development project.&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;... &lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;technology&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;Django&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;... &lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;img/project3.png&amp;#39;&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;... &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;p3&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;save&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Well done for reaching the end of this section! You now know how to create models in Django and build migration files so that you can translate these model classes into database tables. You&amp;rsquo;ve also used the Django shell to create three instances of your model class.&lt;/p&gt;
&lt;p&gt;In the next section, we&amp;rsquo;ll take these three projects you created and create a view function to display them to users on a web page. You can find the &lt;a href=&quot;https://github.com/realpython/materials/tree/0091ee5421f8107e8629f1f22687ff224850b889/rp-portfolio&quot;&gt;source code&lt;/a&gt; for this section of the tutorial on GitHub.&lt;/p&gt;
&lt;h3 id=&quot;projects-app-views&quot;&gt;Projects App: Views&lt;/h3&gt;
&lt;p&gt;Now you&amp;rsquo;ve created the projects to display on your portfolio site, you&amp;rsquo;ll need to create view functions to send the data from the database to the HTML templates.&lt;/p&gt;
&lt;p&gt;In the &lt;code&gt;projects&lt;/code&gt; app, you&amp;rsquo;ll create two different views:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;An index view that shows a snippet of information about each project&lt;/li&gt;
&lt;li&gt;A detail view that shows more information on a particular topic&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Let&amp;rsquo;s start with the index view, as the logic is slightly simpler. Inside &lt;code&gt;views.py&lt;/code&gt;, you&amp;rsquo;ll need to import the &lt;code&gt;Project&lt;/code&gt; class from &lt;code&gt;models.py&lt;/code&gt; and create a function &lt;code&gt;project_index()&lt;/code&gt; that renders a template called &lt;code&gt;project_index.html&lt;/code&gt;. In the body of this function, you&amp;rsquo;ll make a Django ORM query to select all objects in the &lt;code&gt;Project&lt;/code&gt; table:&lt;/p&gt;
&lt;div class=&quot;highlight python&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;lineno&quot;&gt; 1 &lt;/span&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;django.shortcuts&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;render&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 2 &lt;/span&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;projects.models&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Project&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 3 &lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 4 &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;project_index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 5 &lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;projects&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Project&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;objects&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;all&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 6 &lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;context&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 7 &lt;/span&gt;        &lt;span class=&quot;s1&quot;&gt;&amp;#39;projects&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;projects&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 8 &lt;/span&gt;    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 9 &lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;project_index.html&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;There&amp;rsquo;s quite a lot going on in this code block, so let&amp;rsquo;s break it down.&lt;/p&gt;
&lt;p&gt;In &lt;strong&gt;line 5&lt;/strong&gt;, you perform a &lt;strong&gt;query&lt;/strong&gt;. A query is simply a command that allows you to create, retrieve, update, or delete objects (or rows) in your database. In this case, you&amp;rsquo;re retrieving all objects in the &lt;code&gt;projects&lt;/code&gt; table.&lt;/p&gt;
&lt;p&gt;A database query returns a collection of all objects that match the query, known as a &lt;strong&gt;Queryset&lt;/strong&gt;. In this case, you want all objects in the table, so it will return a collection of all projects.&lt;/p&gt;
&lt;p&gt;In &lt;strong&gt;line 6&lt;/strong&gt; of the code block above, we define a dictionary &lt;code&gt;context&lt;/code&gt;. The dictionary only has one entry &lt;code&gt;projects&lt;/code&gt; to which we assign our Queryset containing all projects. The context dictionary is used to send information to our template. Every view function you create needs to have a context dictionary.&lt;/p&gt;
&lt;p&gt;In &lt;strong&gt;line 9&lt;/strong&gt;, &lt;code&gt;context&lt;/code&gt; is added as an argument to &lt;code&gt;render()&lt;/code&gt;. Any entries in the &lt;code&gt;context&lt;/code&gt; dictionary are available in the template, as long as the &lt;code&gt;context&lt;/code&gt; argument is passed to &lt;code&gt;render()&lt;/code&gt;. You&amp;rsquo;ll need to create a context dictionary and pass it to &lt;code&gt;render&lt;/code&gt; in each view function you create.&lt;/p&gt;
&lt;p&gt;We also render a template named &lt;code&gt;project_index.html&lt;/code&gt;, which doesn&amp;rsquo;t exist yet. Don&amp;rsquo;t worry about that for now. You&amp;rsquo;ll create the templates for these views in the next section.&lt;/p&gt;
&lt;p&gt;Next, you&amp;rsquo;ll need to create the &lt;code&gt;project_detail()&lt;/code&gt; view function. This function will need an additional argument: the id of the project that&amp;rsquo;s being viewed.&lt;/p&gt;
&lt;p&gt;Otherwise, the logic is similar:&lt;/p&gt;
&lt;div class=&quot;highlight python&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;lineno&quot;&gt;13 &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;project_detail&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pk&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;14 &lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;project&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Project&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;objects&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pk&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pk&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;15 &lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;context&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;16 &lt;/span&gt;        &lt;span class=&quot;s1&quot;&gt;&amp;#39;project&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;project&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;17 &lt;/span&gt;    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;18 &lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;project_detail.html&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In &lt;strong&gt;line 14&lt;/strong&gt;, we perform another query. This query retrieves the project with primary key, &lt;code&gt;pk&lt;/code&gt;, equal to that in the function argument. We then assign that project in our &lt;code&gt;context&lt;/code&gt; dictionary, which we pass to &lt;code&gt;render()&lt;/code&gt;. Again, there&amp;rsquo;s a template &lt;code&gt;project_detail.html&lt;/code&gt;, which we have yet to create.&lt;/p&gt;
&lt;p&gt;Once your view functions are created, we need to hook them up to URLs. We&amp;rsquo;ll start by creating a file &lt;code&gt;projects/urls.py&lt;/code&gt; to hold the URL configuration for the app. This file should contain the following code:&lt;/p&gt;
&lt;div class=&quot;highlight python&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;lineno&quot;&gt; 1 &lt;/span&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;django.urls&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;path&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 2 &lt;/span&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;views&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 3 &lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 4 &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;urlpatterns&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 5 &lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;views&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;project_index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;project_index&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 6 &lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&amp;lt;int:pk&amp;gt;/&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;views&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;project_detail&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;project_detail&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 7 &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In &lt;strong&gt;line 5&lt;/strong&gt;, we hook up the root URL of our app to the &lt;code&gt;project_index&lt;/code&gt; view. It is slightly more complicated to hook up the &lt;code&gt;project_detail&lt;/code&gt; view. To do this, we want the URL to be &lt;code&gt;/1&lt;/code&gt;, or &lt;code&gt;/2&lt;/code&gt;, and so on, depending on the &lt;code&gt;pk&lt;/code&gt; of the project.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;pk&lt;/code&gt; value in the URL is the same &lt;code&gt;pk&lt;/code&gt; passed to the view function, so you need to dynamically generate these URLs depending on which project you want to view. To do this, we used the &lt;code&gt;&amp;lt;int:pk&amp;gt;&lt;/code&gt; notation. This just tells Django that the value passed in the URL is an integer, and its variable name is &lt;code&gt;pk&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;With those now set up, we need to hook these URLs up to the project URLs. In &lt;code&gt;personal_portfolio/urls.py&lt;/code&gt;, add the following highlighted line of code:&lt;/p&gt;
&lt;div class=&quot;highlight python&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;django.contrib&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;admin&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;django.urls&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;include&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;urlpatterns&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;admin/&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;admin&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;site&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;urls&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
&lt;span class=&quot;hll&quot;&gt;    &lt;span class=&quot;n&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;projects/&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;include&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;projects.urls&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)),&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This line of code includes all the URLs in the projects app but means they are accessed when prefixed by &lt;code&gt;projects/&lt;/code&gt;. There are now two full URLs that can be accessed with our project:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;localhost:8000/projects&lt;/code&gt;:&lt;/strong&gt; The project index page&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;localhost:8000/projects/3&lt;/code&gt;:&lt;/strong&gt; The detail view for the project with &lt;code&gt;pk=3&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These URLs still won&amp;rsquo;t work properly because we don&amp;rsquo;t have any HTML templates. But our views and logic are up and running so all that&amp;rsquo;s left to do is create those templates. If you want to check your code, take a look at the &lt;a href=&quot;https://github.com/realpython/materials/tree/d49c624500e4470107bb258642d2744eeeeefc5a/rp-portfolio&quot;&gt;source code&lt;/a&gt; for this section.&lt;/p&gt;
&lt;h3 id=&quot;projects-app-templates&quot;&gt;Projects App: Templates&lt;/h3&gt;
&lt;p&gt;Phew! You&amp;rsquo;re nearly there with this app. Our final step is to create two templates:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The &lt;code&gt;project_index&lt;/code&gt; template&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;project_detail&lt;/code&gt; template &lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;As we&amp;rsquo;ve added Bootstrap styles to our application, we can use some pre-styled components to make the views look nice. Let&amp;rsquo;s start with the &lt;code&gt;project_index&lt;/code&gt; template.&lt;/p&gt;
&lt;p&gt;For the &lt;code&gt;project_index&lt;/code&gt; template, you&amp;rsquo;ll create a grid of &lt;a href=&quot;https://getbootstrap.com/docs/4.1/components/card/&quot;&gt;Bootstrap cards&lt;/a&gt;, with each card displaying details of the project. Of course, we don&amp;rsquo;t know how many projects there are going to be. In theory, there could be hundreds to display.&lt;/p&gt;
&lt;p&gt;We don&amp;rsquo;t want to have to create 100 different Bootstrap cards and hard-code in all the information to each project. Instead, we&amp;rsquo;re going to use a feature of the Django template engine: &lt;a href=&quot;https://realpython.com/python-for-loop/&quot;&gt;&lt;strong&gt;for loops&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Using this feature, you&amp;rsquo;ll be able to loop through all the projects and create a card for each one. The for loop syntax in the Django template engine is as follows:&lt;/p&gt;
&lt;div class=&quot;highlight htmldjango&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;project&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;projects&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;{# Do something... #}&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;endfor&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now that you know how for loops work, you can add the following code to a file named &lt;code&gt;projects/templates/project_index.html&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight htmldjango&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;lineno&quot;&gt; 1 &lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;base.html&amp;quot;&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 2 &lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;load&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 3 &lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;block&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;page_content&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 4 &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;h1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;Projects&lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;h1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 5 &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;row&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 6 &lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;project&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;projects&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 7 &lt;/span&gt;    &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;col-md-4&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 8 &lt;/span&gt;        &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;card mb-2&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 9 &lt;/span&gt;            &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;img&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;card-img-top&amp;quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;project.image&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;10 &lt;/span&gt;            &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;card-body&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;11 &lt;/span&gt;                &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;h5&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;card-title&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;project.title&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;h5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;12 &lt;/span&gt;                &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;card-text&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;project.description&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;13 &lt;/span&gt;                &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;url&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;project_detail&amp;#39;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;project.pk&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;14 &lt;/span&gt;                   &lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;btn btn-primary&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;15 &lt;/span&gt;                    Read More
&lt;span class=&quot;lineno&quot;&gt;16 &lt;/span&gt;                &lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;17 &lt;/span&gt;            &lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;18 &lt;/span&gt;        &lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;19 &lt;/span&gt;    &lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;20 &lt;/span&gt;    &lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;endfor&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;21 &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;22 &lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;endblock&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;There&amp;rsquo;s a lot of Bootstrap HTML here, which is not the focus of this tutorial. Feel free to copy and paste and take a look at the Bootstrap docs if you&amp;rsquo;re interested in learning more. Instead of focusing on the Bootstrap, there are a few things to highlight in this code block.&lt;/p&gt;
&lt;p&gt;In &lt;strong&gt;line 1&lt;/strong&gt;, we extend &lt;code&gt;base.html&lt;/code&gt; as we did in the &lt;em&gt;Hello, World!&lt;/em&gt; app tutorial. I&amp;rsquo;ve added some more styling to this file to include a &lt;a href=&quot;https://getbootstrap.com/docs/4.1/components/navbar/&quot;&gt;navigation bar&lt;/a&gt; and so that all the content is contained in a &lt;a href=&quot;https://getbootstrap.com/docs/4.1/layout/overview/#containers&quot;&gt;Bootstrap container&lt;/a&gt;. The changes to &lt;code&gt;base.html&lt;/code&gt; can be seen in the &lt;a href=&quot;https://github.com/realpython/materials/blob/get-started-with-django-part-1/rp-portfolio/personal_portfolio/templates/base.html&quot;&gt;source code&lt;/a&gt; on GitHub.&lt;/p&gt;
&lt;p&gt;On &lt;strong&gt;line 2&lt;/strong&gt;, we include a &lt;code&gt;{% load static %}&lt;/code&gt; tag to include static files such as images. Remember back in the section on Django models, when you created the &lt;code&gt;Project&lt;/code&gt; model. One of its attributes was a filepath. That filepath is where we&amp;rsquo;re going to store the actual images for each project.&lt;/p&gt;
&lt;p&gt;Django automatically registers static files stored in a directory named &lt;code&gt;static/&lt;/code&gt; in each application. Our image file path names were of the structure: &lt;code&gt;img/&amp;lt;photo_name&amp;gt;.png&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;When loading static files, Django looks in the &lt;code&gt;static/&lt;/code&gt; directory for files matching a given filepath within &lt;code&gt;static/&lt;/code&gt;. So, we need to create a directory named &lt;code&gt;static/&lt;/code&gt; with another directory named &lt;code&gt;img/&lt;/code&gt; inside. Inside &lt;code&gt;img/&lt;/code&gt;, you can copy over the images from the &lt;a href=&quot;https://github.com/realpython/materials/tree/7909f5a682a88d8488167bc6fe9b64a5b294f99a/rp-portfolio/projects/static/img&quot;&gt;source code&lt;/a&gt; on GitHub.&lt;/p&gt;
&lt;p&gt;On &lt;strong&gt;line 6&lt;/strong&gt;, we begin the for loop, looping over all projects passed in by the &lt;code&gt;context&lt;/code&gt; dictionary.&lt;/p&gt;
&lt;p&gt;Inside this for loop, we can access each individual project. To access the project&amp;rsquo;s attributes, you can use dot notation inside double curly brackets. For example, to access the project&amp;rsquo;s title, you use &lt;code&gt;{{ project.title }}&lt;/code&gt;. The same notation can be used to access any of the project&amp;rsquo;s attributes.&lt;/p&gt;
&lt;p&gt;On &lt;strong&gt;line 9&lt;/strong&gt;, we include our project image. Inside the &lt;code&gt;src&lt;/code&gt; attribute, we add the code &lt;code&gt;{% static project.image %}&lt;/code&gt;. This tells Django to look inside the static files to find a file matching &lt;code&gt;project.image&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The final point that we need to highlight is the link on &lt;strong&gt;line 13&lt;/strong&gt;. This is the link to our &lt;code&gt;project_detail&lt;/code&gt; page. Accessing URLs in Django is similar to accessing static files. The code for the URL has the following form:&lt;/p&gt;
&lt;div class=&quot;highlight htmldjango&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;url&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;&amp;lt;url path name&amp;gt;&amp;#39;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;view_function_arguments&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In this case, we are accessing a URL path named &lt;code&gt;project_detail&lt;/code&gt;, which takes integer arguments corresponding to the &lt;code&gt;pk&lt;/code&gt; number of the project.&lt;/p&gt;
&lt;p&gt;With all that in place, if you start the Django server and visit &lt;code&gt;localhost:8000/projects&lt;/code&gt;, then you should see something like this:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://files.realpython.com/media/Screenshot_2018-12-16_at_16.46.36.a71c744f096a.png&quot; target=&quot;_blank&quot;&gt;&lt;img class=&quot;img-fluid mx-auto d-block &quot; src=&quot;https://files.realpython.com/media/Screenshot_2018-12-16_at_16.46.36.a71c744f096a.png&quot; width=&quot;2784&quot; height=&quot;1628&quot; srcset=&quot;https://robocrop.realpython.net/?url=https%3A//files.realpython.com/media/Screenshot_2018-12-16_at_16.46.36.a71c744f096a.png&amp;amp;w=696&amp;amp;sig=712e1edbd4e78895079933d316f34aa93a6687ce 696w, https://robocrop.realpython.net/?url=https%3A//files.realpython.com/media/Screenshot_2018-12-16_at_16.46.36.a71c744f096a.png&amp;amp;w=1392&amp;amp;sig=99292d6c026f3910d493f30d1dcf35a12c3d6276 1392w, https://files.realpython.com/media/Screenshot_2018-12-16_at_16.46.36.a71c744f096a.png 2784w&quot; sizes=&quot;75vw&quot; alt=&quot;project index view&quot;/&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;With the &lt;code&gt;project_index.html&lt;/code&gt; template in place, it&amp;rsquo;s time to create the &lt;code&gt;project_detail.html&lt;/code&gt; template. The code for this template is below:&lt;/p&gt;
&lt;div class=&quot;highlight htmldjango&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;base.html&amp;quot;&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;load&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;

&lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;block&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;page_content&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;h1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;project.title&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;h1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;row&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;col-md-8&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;img&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;project.image&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;alt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;&amp;quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;100%&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;col-md-4&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;h5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;About the project:&lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;h5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;project.description&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;br&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;h5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;Technology used:&lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;h5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;project.technology&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;endblock&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The code in this template has the same functionality as each project card in the &lt;code&gt;project_index.html&lt;/code&gt; template. The only difference is the introduction of some Bootstrap columns.&lt;/p&gt;
&lt;p&gt;If you visit &lt;code&gt;localhost:8000/projects/1&lt;/code&gt;, you should see the detail page for that first project you created:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://files.realpython.com/media/Screenshot_2018-12-16_at_16.50.59.43297d79452f.png&quot; target=&quot;_blank&quot;&gt;&lt;img class=&quot;img-fluid mx-auto d-block &quot; src=&quot;https://files.realpython.com/media/Screenshot_2018-12-16_at_16.50.59.43297d79452f.png&quot; width=&quot;2784&quot; height=&quot;1628&quot; srcset=&quot;https://robocrop.realpython.net/?url=https%3A//files.realpython.com/media/Screenshot_2018-12-16_at_16.50.59.43297d79452f.png&amp;amp;w=696&amp;amp;sig=3218b4a2f2b423329bc9ccccfa2da8075ac41eb0 696w, https://robocrop.realpython.net/?url=https%3A//files.realpython.com/media/Screenshot_2018-12-16_at_16.50.59.43297d79452f.png&amp;amp;w=1392&amp;amp;sig=01afcc50cae869f730605e67b1b951886afbe408 1392w, https://files.realpython.com/media/Screenshot_2018-12-16_at_16.50.59.43297d79452f.png 2784w&quot; sizes=&quot;75vw&quot; alt=&quot;project detail view&quot;/&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;In this section, you learned how to use models, views, and templates to create a fully functioning app for your personal portfolio project. Check out the &lt;a href=&quot;https://github.com/realpython/materials/tree/7909f5a682a88d8488167bc6fe9b64a5b294f99a/rp-portfolio&quot;&gt;source code&lt;/a&gt; for this section on GitHub.&lt;/p&gt;
&lt;p&gt;In the next section, you&amp;rsquo;ll build a fully functioning blog for your site, and you&amp;rsquo;ll also learn about the Django admin page and forms.&lt;/p&gt;
&lt;h2 id=&quot;share-your-knowledge-with-a-blog&quot;&gt;Share Your Knowledge With a Blog&lt;/h2&gt;
&lt;p&gt;A blog is a great addition to any personal portfolio site. Whether you update it monthly or weekly, it&amp;rsquo;s a great place to share your knowledge as you learn. In this section, you&amp;rsquo;re going to build a fully functioning blog that will allow you to perform the following tasks:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Create, update, and delete blog posts&lt;/li&gt;
&lt;li&gt;Display posts to the user as either an index view or a detail view&lt;/li&gt;
&lt;li&gt;Assign categories to posts&lt;/li&gt;
&lt;li&gt;Allow users to comment on posts&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You&amp;rsquo;ll also learn how to use the Django Admin interface, which is where you&amp;rsquo;ll create, update, and delete posts and categories as necessary.&lt;/p&gt;
&lt;p&gt;Before you get into building out the functionality of this part of your site, create a new Django app named &lt;code&gt;blog&lt;/code&gt;. Don&amp;rsquo;t delete &lt;code&gt;projects&lt;/code&gt;. You&amp;rsquo;ll want both apps in your Django project:&lt;/p&gt;
&lt;div class=&quot;highlight sh&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; python manage.py startapp blog
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This may start to feel familiar to you, as its your third time doing this. Don&amp;rsquo;t forget to add &lt;code&gt;blog&lt;/code&gt; to your &lt;code&gt;INSTALLED_APPS&lt;/code&gt; in &lt;code&gt;personal_porfolio/settings.py&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight python&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;INSTALLED_APPS&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;s2&quot;&gt;&amp;quot;django.contrib.admin&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s2&quot;&gt;&amp;quot;django.contrib.auth&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s2&quot;&gt;&amp;quot;django.contrib.contenttypes&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s2&quot;&gt;&amp;quot;django.contrib.sessions&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s2&quot;&gt;&amp;quot;django.contrib.messages&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s2&quot;&gt;&amp;quot;django.contrib.staticfiles&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s2&quot;&gt;&amp;quot;projects&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;hll&quot;&gt;    &lt;span class=&quot;s2&quot;&gt;&amp;quot;blog&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Hold off on hooking up the URLs for now. As with the &lt;code&gt;projects&lt;/code&gt; app, you&amp;rsquo;ll start by adding your models.&lt;/p&gt;
&lt;h3 id=&quot;blog-app-models&quot;&gt;Blog App: Models&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;models.py&lt;/code&gt; file in this app is much more complicated than in the &lt;code&gt;projects&lt;/code&gt; app.&lt;/p&gt;
&lt;p&gt;You&amp;rsquo;re going to need three separate database tables for the blog: &lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;Post&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Category&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Comment&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;These tables need to be related to one another. This is made easier because Django models come with fields specifically for this purpose.&lt;/p&gt;
&lt;p&gt;Below is the code for the &lt;code&gt;Category&lt;/code&gt; and &lt;code&gt;Post&lt;/code&gt; models:&lt;/p&gt;
&lt;div class=&quot;highlight python&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;lineno&quot;&gt; 1 &lt;/span&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;django.db&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;models&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 2 &lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 3 &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Category&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;models&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 4 &lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;models&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CharField&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;max_length&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 5 &lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 6 &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Post&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;models&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 7 &lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;title&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;models&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CharField&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;max_length&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;255&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 8 &lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;body&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;models&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TextField&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 9 &lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;created_on&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;models&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;DateTimeField&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;auto_now_add&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;10 &lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;last_modified&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;models&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;DateTimeField&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;auto_now&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;11 &lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;categories&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;models&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ManyToManyField&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;Category&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;related_name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;posts&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;Category&lt;/code&gt; model is very simple. All that&amp;rsquo;s needed is a single &lt;code&gt;CharField&lt;/code&gt; in which we store the name of the category.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;title&lt;/code&gt; and &lt;code&gt;body&lt;/code&gt; fields on the &lt;code&gt;Post&lt;/code&gt; model are the same field types as you used in the &lt;code&gt;Project&lt;/code&gt; model. We only need a &lt;code&gt;CharField&lt;/code&gt; for the &lt;code&gt;title&lt;/code&gt; as we only want a short string for the post title. The body needs to be a long-form piece of text, so we use a &lt;code&gt;TextField&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The next two fields, &lt;code&gt;created_on&lt;/code&gt; and &lt;code&gt;last_modified&lt;/code&gt;, are Django &lt;code&gt;DateTimeFields&lt;/code&gt;. These store a &lt;a href=&quot;https://docs.python.org/3.7/library/datetime.html&quot;&gt;&lt;code&gt;datetime&lt;/code&gt;&lt;/a&gt; object containing the date and time when the post was created and modified respectively.&lt;/p&gt;
&lt;p&gt;On &lt;strong&gt;line 9&lt;/strong&gt;, the &lt;code&gt;DateTimeField&lt;/code&gt; takes an argument &lt;code&gt;auto_now_add=True&lt;/code&gt;. This assigns the current date and time to this field whenever an instance of this class is created.&lt;/p&gt;
&lt;p&gt;On &lt;strong&gt;line 10&lt;/strong&gt;, the &lt;code&gt;DateTimeField&lt;/code&gt; takes an argument &lt;code&gt;auto_now=True&lt;/code&gt;. This assigns the current date and time to this field whenever an instance of this class is saved. That means whenever you edit an instance of this class, the &lt;code&gt;date_modified&lt;/code&gt; is updated.&lt;/p&gt;
&lt;p&gt;The final field on the post model is the most interesting. We want to link our models for categories and posts in such a way that &lt;em&gt;many&lt;/em&gt; categories can be assigned to &lt;em&gt;many&lt;/em&gt; posts. Luckily, Django makes this easier for us by providing a &lt;code&gt;ManytoManyField&lt;/code&gt; field type. This field links the &lt;code&gt;Post&lt;/code&gt; and &lt;code&gt;Category&lt;/code&gt; models and allows us to create a relationship between the two tables.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;ManyToManyField&lt;/code&gt; takes two arguments. The first is the model with which the relationship is, in this case its &lt;code&gt;Category&lt;/code&gt;. The second allows us to access the relationship from a &lt;code&gt;Category&lt;/code&gt; object, even though we haven&amp;rsquo;t added a field there. By adding a &lt;code&gt;related_name&lt;/code&gt; of &lt;code&gt;posts&lt;/code&gt;, we can access &lt;code&gt;category.posts&lt;/code&gt; to give us a list of posts with that category.&lt;/p&gt;
&lt;p&gt;The third and final model we need to add is &lt;code&gt;Comment&lt;/code&gt;. We&amp;rsquo;ll use another relationship field similar the &lt;code&gt;ManyToManyField&lt;/code&gt; that relates &lt;code&gt;Post&lt;/code&gt; and &lt;code&gt;Category&lt;/code&gt;. However, we only want the relationship to go one way: one post should have many comments.&lt;/p&gt;
&lt;p&gt;You&amp;rsquo;ll see how this works after we define the &lt;code&gt;Comment&lt;/code&gt; class:&lt;/p&gt;
&lt;div class=&quot;highlight python&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;lineno&quot;&gt;16 &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Comment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;models&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;17 &lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;author&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;models&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CharField&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;max_length&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;60&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;18 &lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;body&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;models&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TextField&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;19 &lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;created_on&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;models&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;DateTimeField&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;auto_now_add&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;20 &lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;post&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;models&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ForeignKey&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;Post&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;on_delete&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;models&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CASCADE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The first three fields on this model should look familiar. There&amp;rsquo;s an &lt;code&gt;author&lt;/code&gt; field for users to add a name or alias, a &lt;code&gt;body&lt;/code&gt; field for the body of the comment, and a &lt;code&gt;created_on&lt;/code&gt; field that is identical to the &lt;code&gt;created_on&lt;/code&gt; field on the &lt;code&gt;Post&lt;/code&gt; model.&lt;/p&gt;
&lt;p&gt;On &lt;strong&gt;line 20&lt;/strong&gt;, we use another relational field, the &lt;code&gt;ForeignKey&lt;/code&gt; field. This is similar to the &lt;code&gt;ManyToManyField&lt;/code&gt; but instead defines a &lt;strong&gt;many to one&lt;/strong&gt; relationship. The reasoning behind this is that &lt;strong&gt;many&lt;/strong&gt; comments can be assigned to &lt;strong&gt;one&lt;/strong&gt; post. But you can&amp;rsquo;t have a comment that corresponds to many posts.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;ForeignKey&lt;/code&gt; field takes two arguments. The first is the other model in the relationship, in this case, &lt;code&gt;Post&lt;/code&gt;. The second tells Django what to do when a post is deleted. If a post is deleted, then we don&amp;rsquo;t want the comments related to it hanging around. We, therefore, want to delete them as well, so we add the argument &lt;code&gt;on_delete=models.CASCADE&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Once you&amp;rsquo;ve created the models, you can create the migration files with &lt;code&gt;makemigrations&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight sh&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; python manage.py makemigrations blog
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The final step is to migrate the tables. This time, don&amp;rsquo;t add the app-specific flag. Later on, you&amp;rsquo;ll need the &lt;code&gt;User&lt;/code&gt; model that Django creates for you:&lt;/p&gt;
&lt;div class=&quot;highlight sh&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; python manage.py migrate
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now that you&amp;rsquo;ve created the models, we can start to add some posts and categories. You won&amp;rsquo;t be doing this from the command line as you did with the projects, as typing out a whole blog post into the command line would be unpleasant to say the least! &lt;/p&gt;
&lt;p&gt;Instead, you&amp;rsquo;ll learn how to use the Django Admin, which will allow you to create instances of your model classes in a nice web interface.&lt;/p&gt;
&lt;p&gt;Don&amp;rsquo;t forget that you can check out the &lt;a href=&quot;https://github.com/realpython/materials/tree/6fdccb8ae85c5792e3639c406be09abc2d4803d8/rp-portfolio&quot;&gt;source code&lt;/a&gt; for this section on GitHub before moving onto the next section.&lt;/p&gt;
&lt;h3 id=&quot;blog-app-django-admin&quot;&gt;Blog App: Django Admin&lt;/h3&gt;
&lt;p&gt;The Django Admin is a fantastic tool and one of the great benefits of using Django. As you&amp;rsquo;re the only person who&amp;rsquo;s going to be writing blog posts and creating categories, there&amp;rsquo;s no need to create a user interface to do so.&lt;/p&gt;
&lt;p&gt;On the other hand, you don&amp;rsquo;t want to have to write blog posts in the command line. This is where the admin comes in. It allows you to create, update, and delete instances of your model classes and provides a nice interface for doing so.&lt;/p&gt;
&lt;p&gt;Before you can access the admin, you need to add yourself as a superuser. This is why, in the previous section, you applied migrations project-wide as opposed to just for the app. Django comes with built-in user models and a user management system that will allow you to login to the admin.&lt;/p&gt;
&lt;p&gt;To start off, you can add yourself as superuser using the following command:&lt;/p&gt;
&lt;div class=&quot;highlight sh&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; python manage.py createsuperuser
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You&amp;rsquo;ll then be prompted to enter a username followed by your email address and password. Once you&amp;rsquo;ve entered the required details, you&amp;rsquo;ll be notified that the superuser has been created. Don&amp;rsquo;t worry if you make a mistake since you can just start again:&lt;/p&gt;
&lt;div class=&quot;highlight sh&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;go&quot;&gt;Username (leave blank to use &amp;#39;jasmine&amp;#39;): jfiner&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Email address: jfiner@example.com&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Password:&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Password (again):&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Superuser created successfully.&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Navigate to &lt;code&gt;localhost:8000/admin&lt;/code&gt; and log in with the credentials you just used to create a superuser. You&amp;rsquo;ll see a page similar to the one below:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://files.realpython.com/media/Screenshot_2018-12-16_at_19.18.42.ee6fb5185d8a.png&quot; target=&quot;_blank&quot;&gt;&lt;img class=&quot;img-fluid mx-auto d-block &quot; src=&quot;https://files.realpython.com/media/Screenshot_2018-12-16_at_19.18.42.ee6fb5185d8a.png&quot; width=&quot;2784&quot; height=&quot;1628&quot; srcset=&quot;https://robocrop.realpython.net/?url=https%3A//files.realpython.com/media/Screenshot_2018-12-16_at_19.18.42.ee6fb5185d8a.png&amp;amp;w=696&amp;amp;sig=a1a3abf6fd548926dc4a1ccc84f8a9827192a3c6 696w, https://robocrop.realpython.net/?url=https%3A//files.realpython.com/media/Screenshot_2018-12-16_at_19.18.42.ee6fb5185d8a.png&amp;amp;w=1392&amp;amp;sig=1efcdf95988c118a5118ccf17af84a488df7a910 1392w, https://files.realpython.com/media/Screenshot_2018-12-16_at_19.18.42.ee6fb5185d8a.png 2784w&quot; sizes=&quot;75vw&quot; alt=&quot;The Default Django Admin&quot;/&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The User and Groups models should appear, but you&amp;rsquo;ll notice that there&amp;rsquo;s no reference to the models you&amp;rsquo;ve created yourself. That&amp;rsquo;s because you need to register them inside the admin.&lt;/p&gt;
&lt;p&gt;In the &lt;code&gt;blog&lt;/code&gt; directory, open the file &lt;code&gt;admin.py&lt;/code&gt; and type the following lines of code:&lt;/p&gt;
&lt;div class=&quot;highlight python&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;lineno&quot;&gt; 1 &lt;/span&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;django.contrib&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;admin&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 2 &lt;/span&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;blog.models&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Post&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Category&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 3 &lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 4 &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;PostAdmin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;admin&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ModelAdmin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 5 &lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;pass&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 6 &lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 7 &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;CategoryAdmin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;admin&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ModelAdmin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 8 &lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;pass&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 9 &lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;10 &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;admin&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;site&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;register&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Post&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PostAdmin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;11 &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;admin&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;site&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;register&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Category&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CategoryAdmin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;On &lt;strong&gt;line 2&lt;/strong&gt;, you import the models you want to register on the admin page.&lt;/p&gt;
&lt;div class=&quot;alert alert-primary&quot; role=&quot;alert&quot;&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; We&amp;rsquo;re not adding the comments to the admin. That&amp;rsquo;s because it&amp;rsquo;s not usually necessary to edit or create comments yourself.&lt;/p&gt;
&lt;p&gt;If you wanted to add a feature where comments are moderated, then go ahead and add the Comments model too. The steps to do so are exactly the same!&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;On &lt;strong&gt;line 4&lt;/strong&gt; and &lt;strong&gt;line 7&lt;/strong&gt;, you define empty classes &lt;code&gt;PostAdmin&lt;/code&gt; and &lt;code&gt;CategoryAdmin&lt;/code&gt;. For the purposes of this tutorial, you don&amp;rsquo;t need to add any attributes or methods to these classes. They are used to customize what is shown on the admin pages. For this tutorial, the default configuration is enough.&lt;/p&gt;
&lt;p&gt;The last two lines are the most important. These register the models with the admin classes. If you now visit &lt;code&gt;localhost:8000/admin&lt;/code&gt;, then you should see that the &lt;code&gt;Post&lt;/code&gt; and &lt;code&gt;Category&lt;/code&gt; models are now visible:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://files.realpython.com/media/Screenshot_2018-12-16_at_19.19.20.297b0ccfe2f3.png&quot; target=&quot;_blank&quot;&gt;&lt;img class=&quot;img-fluid mx-auto d-block &quot; src=&quot;https://files.realpython.com/media/Screenshot_2018-12-16_at_19.19.20.297b0ccfe2f3.png&quot; width=&quot;2784&quot; height=&quot;1628&quot; srcset=&quot;https://robocrop.realpython.net/?url=https%3A//files.realpython.com/media/Screenshot_2018-12-16_at_19.19.20.297b0ccfe2f3.png&amp;amp;w=696&amp;amp;sig=ea38f98ec131073e2a079638ce06962fa72364ee 696w, https://robocrop.realpython.net/?url=https%3A//files.realpython.com/media/Screenshot_2018-12-16_at_19.19.20.297b0ccfe2f3.png&amp;amp;w=1392&amp;amp;sig=e89958435c80771497a510e5ebd2a34ead4c763a 1392w, https://files.realpython.com/media/Screenshot_2018-12-16_at_19.19.20.297b0ccfe2f3.png 2784w&quot; sizes=&quot;75vw&quot; alt=&quot;Django Admin with Posts and Categories&quot;/&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;If you click into &lt;em&gt;Posts&lt;/em&gt; or &lt;em&gt;Categorys&lt;/em&gt;,  you should be able to add new instances of both models. I like to add the text of fake blog posts by using &lt;a href=&quot;https://www.lipsum.com/&quot;&gt;lorem ipsum&lt;/a&gt; dummy text.&lt;/p&gt;
&lt;p&gt;Create a couple of fake posts and assign them fake categories before moving onto the next section. That way, you&amp;rsquo;ll have posts you can view when we create our templates.&lt;/p&gt;
&lt;p&gt;Don&amp;rsquo;t forget to check out the &lt;a href=&quot;https://github.com/realpython/materials/tree/86c5009b84ef207c6dd1873ec9dc25afbe725347/rp-portfolio&quot;&gt;source code&lt;/a&gt; for this section before moving on to building out the views for our app.&lt;/p&gt;
&lt;h3 id=&quot;blog-app-views&quot;&gt;Blog App: Views&lt;/h3&gt;
&lt;p&gt;You&amp;rsquo;ll need to create three view functions in the &lt;code&gt;views.py&lt;/code&gt; file in the &lt;code&gt;blog&lt;/code&gt; directory:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;blog_index&lt;/code&gt;&lt;/strong&gt; will display a list of all your posts.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;blog_detail&lt;/code&gt;&lt;/strong&gt; will display the full post as well as comments and a form to allow users to create new comments.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;blog_category&lt;/code&gt;&lt;/strong&gt; will be similar to &lt;code&gt;blog_index&lt;/code&gt;, but the posts viewed will only be of a specific category chosen by the user.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The simplest view function to start with is &lt;code&gt;blog_index()&lt;/code&gt;. This will be very similar to the &lt;code&gt;project_index()&lt;/code&gt; view from your &lt;code&gt;project&lt;/code&gt; app. You&amp;rsquo;ll just query the &lt;code&gt;Post&lt;/code&gt; models and retrieve all its objects:&lt;/p&gt;
&lt;div class=&quot;highlight python&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;lineno&quot;&gt; 1 &lt;/span&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;django.shortcuts&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;render&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 2 &lt;/span&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;blog.models&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Post&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 3 &lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 4 &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;blog_index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 5 &lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;posts&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Post&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;objects&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;all&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;order_by&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;-created_on&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 6 &lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;context&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 7 &lt;/span&gt;        &lt;span class=&quot;s2&quot;&gt;&amp;quot;posts&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;posts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 8 &lt;/span&gt;    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 9 &lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;blog_index.html&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;On &lt;strong&gt;line 2&lt;/strong&gt;, you import the &lt;code&gt;Post&lt;/code&gt; model, and on &lt;strong&gt;line 5&lt;/strong&gt; inside the view function, you obtain a Queryset containing all the posts in the database. &lt;code&gt;order_by()&lt;/code&gt; orders the Queryset according to the argument given. The minus sign tells Django to start with the largest value rather than the smallest. We use this, as we want the posts to be ordered with the most recent post first.&lt;/p&gt;
&lt;p&gt;Finally, you define the &lt;code&gt;context&lt;/code&gt; dictionary and render the template. Don&amp;rsquo;t worry about creating it yet. You&amp;rsquo;ll get to creating those in the next section.&lt;/p&gt;
&lt;p&gt;Next, you can start to create the &lt;code&gt;blog_category()&lt;/code&gt; view. The view function will need to take a category name as an argument and query the &lt;code&gt;Post&lt;/code&gt; database for all posts that have been assigned the given category:&lt;/p&gt;
&lt;div class=&quot;highlight python&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;lineno&quot;&gt;13 &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;blog_category&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;category&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;14 &lt;/span&gt;&lt;span class=&quot;hll&quot;&gt;    &lt;span class=&quot;n&quot;&gt;posts&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Post&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;objects&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;lineno&quot;&gt;15 &lt;/span&gt;&lt;span class=&quot;hll&quot;&gt;        &lt;span class=&quot;n&quot;&gt;categories__name__contains&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;category&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;lineno&quot;&gt;16 &lt;/span&gt;&lt;span class=&quot;hll&quot;&gt;    &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;order_by&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;lineno&quot;&gt;17 &lt;/span&gt;&lt;span class=&quot;hll&quot;&gt;        &lt;span class=&quot;s1&quot;&gt;&amp;#39;-created_on&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;lineno&quot;&gt;18 &lt;/span&gt;&lt;span class=&quot;hll&quot;&gt;    &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;lineno&quot;&gt;19 &lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;context&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;20 &lt;/span&gt;        &lt;span class=&quot;s2&quot;&gt;&amp;quot;category&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;category&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;21 &lt;/span&gt;        &lt;span class=&quot;s2&quot;&gt;&amp;quot;posts&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;posts&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;22 &lt;/span&gt;    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;23 &lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;blog_category.html&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;On &lt;strong&gt;line 14&lt;/strong&gt;, you&amp;rsquo;ve used a &lt;a href=&quot;https://docs.djangoproject.com/en/2.1/topics/db/queries/#retrieving-specific-objects-with-filters&quot;&gt;Django Queryset filter&lt;/a&gt;. The argument of the filter tells Django what conditions need to be met for an object to be retrieved. In this case, we only want posts whose categories contain the category with the name corresponding to that given in the argument of the view function. Again, you&amp;rsquo;re using &lt;code&gt;order_by()&lt;/code&gt; to order posts starting with the most recent.&lt;/p&gt;
&lt;p&gt;We then add these posts and the category to the &lt;code&gt;context&lt;/code&gt; dictionary, and render our template.&lt;/p&gt;
&lt;p&gt;The last view function to add is &lt;code&gt;blog_detail()&lt;/code&gt;. This is more complicated as we are going to include a form. Before you add the form, just set up the view function to show a specific post with a comment associated with it. This function will be almost equivalent to the &lt;code&gt;project_detail()&lt;/code&gt; view function in the &lt;code&gt;projects&lt;/code&gt; app:&lt;/p&gt;
&lt;div class=&quot;highlight python&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;lineno&quot;&gt;21 &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;blog_detail&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pk&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;22 &lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;post&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Post&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;objects&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pk&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pk&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;23 &lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;comments&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Comment&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;objects&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;post&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;post&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;24 &lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;context&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;25 &lt;/span&gt;        &lt;span class=&quot;s2&quot;&gt;&amp;quot;post&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;post&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;26 &lt;/span&gt;        &lt;span class=&quot;s2&quot;&gt;&amp;quot;comments&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;comments&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;27 &lt;/span&gt;    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;28 &lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;29 &lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;blog_detail.html&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The view function takes a &lt;code&gt;pk&lt;/code&gt; value as an argument and, on &lt;strong&gt;line 22&lt;/strong&gt;, retrieves the object with the given &lt;code&gt;pk&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;On &lt;strong&gt;line 23&lt;/strong&gt;, we retrieve all the comments assigned to the given post using Django filters again.&lt;/p&gt;
&lt;p&gt;Lastly, add both &lt;code&gt;post&lt;/code&gt; and &lt;code&gt;comments&lt;/code&gt; to the &lt;code&gt;context&lt;/code&gt; dictionary and render the template.&lt;/p&gt;
&lt;p&gt;To add a form to the page, you&amp;rsquo;ll need to create another file in the &lt;code&gt;blog&lt;/code&gt; directory named &lt;code&gt;forms.py&lt;/code&gt;. Django forms are very similar to models. A form consists of a class where the class attributes are form fields. Django comes with some built-in form fields that you can use to quickly create the form you need.&lt;/p&gt;
&lt;p&gt;For this form, the only fields you&amp;rsquo;ll need are &lt;code&gt;author&lt;/code&gt;, which should be a &lt;code&gt;CharField&lt;/code&gt;, and &lt;code&gt;body&lt;/code&gt;, which can also be a &lt;code&gt;CharField&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;alert alert-primary&quot; role=&quot;alert&quot;&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; If the &lt;code&gt;CharField&lt;/code&gt; of your form corresponds to a model &lt;code&gt;CharField&lt;/code&gt;, make sure both have the same &lt;code&gt;max_length&lt;/code&gt; value.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;&lt;code&gt;blog/forms.py&lt;/code&gt; should contain the following code:&lt;/p&gt;
&lt;div class=&quot;highlight python&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;django&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;forms&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;CommentForm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;forms&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Form&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;author&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;forms&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CharField&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;max_length&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;60&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;widget&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;forms&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TextInput&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;attrs&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;s2&quot;&gt;&amp;quot;class&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;form-control&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;s2&quot;&gt;&amp;quot;placeholder&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;Your Name&amp;quot;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;body&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;forms&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CharField&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;widget&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;forms&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Textarea&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;attrs&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;s2&quot;&gt;&amp;quot;class&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;form-control&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;s2&quot;&gt;&amp;quot;placeholder&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;Leave a comment!&amp;quot;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You&amp;rsquo;ll also notice an argument &lt;code&gt;widget&lt;/code&gt; has been passed to both the fields. The &lt;code&gt;author&lt;/code&gt; field has the &lt;code&gt;forms.TextInput&lt;/code&gt; widget. This tells Django to load this field as an HTML text input element in the templates. The &lt;code&gt;body&lt;/code&gt; field uses a &lt;code&gt;forms.TextArea&lt;/code&gt; widget instead, so that the field is rendered as an HTML text area element.&lt;/p&gt;
&lt;p&gt;These widgets also take an argument &lt;code&gt;attrs&lt;/code&gt;, which is a dictionary and allows us to specify some CSS classes, which will help with formatting the template for this view later. It also allows us to add some placeholder text.&lt;/p&gt;
&lt;p&gt;When a form is posted, a &lt;code&gt;POST&lt;/code&gt; request is sent to the server. So, in the view function, we need to check if a &lt;code&gt;POST&lt;/code&gt; request has been received. We can then create a comment from the form fields. Django comes with a handy &lt;code&gt;is_valid()&lt;/code&gt; on its forms, so we can check that all the fields have been entered correctly.&lt;/p&gt;
&lt;p&gt;Once you&amp;rsquo;ve created the comment from the form, you&amp;rsquo;ll need to save it using &lt;code&gt;save()&lt;/code&gt; and then query the database for all the comments assigned to the given post. Your view function should contain the following code:&lt;/p&gt;
&lt;div class=&quot;highlight python&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;lineno&quot;&gt;21 &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;blog_detail&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pk&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;22 &lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;post&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Post&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;objects&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pk&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pk&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;23 &lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;24 &lt;/span&gt;&lt;span class=&quot;hll&quot;&gt;    &lt;span class=&quot;n&quot;&gt;form&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CommentForm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;lineno&quot;&gt;25 &lt;/span&gt;&lt;span class=&quot;hll&quot;&gt;    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;method&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;POST&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;lineno&quot;&gt;26 &lt;/span&gt;&lt;span class=&quot;hll&quot;&gt;        &lt;span class=&quot;n&quot;&gt;form&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CommentForm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;POST&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;lineno&quot;&gt;27 &lt;/span&gt;&lt;span class=&quot;hll&quot;&gt;        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;form&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;is_valid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;lineno&quot;&gt;28 &lt;/span&gt;&lt;span class=&quot;hll&quot;&gt;            &lt;span class=&quot;n&quot;&gt;comment&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Comment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;lineno&quot;&gt;29 &lt;/span&gt;&lt;span class=&quot;hll&quot;&gt;                &lt;span class=&quot;n&quot;&gt;author&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;form&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cleaned_data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;author&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;lineno&quot;&gt;30 &lt;/span&gt;&lt;span class=&quot;hll&quot;&gt;                &lt;span class=&quot;n&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;form&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cleaned_data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;body&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;lineno&quot;&gt;31 &lt;/span&gt;&lt;span class=&quot;hll&quot;&gt;                &lt;span class=&quot;n&quot;&gt;post&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;post&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;lineno&quot;&gt;32 &lt;/span&gt;&lt;span class=&quot;hll&quot;&gt;            &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;lineno&quot;&gt;33 &lt;/span&gt;&lt;span class=&quot;hll&quot;&gt;            &lt;span class=&quot;n&quot;&gt;comment&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;save&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;lineno&quot;&gt;34 &lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;35 &lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;comments&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Comment&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;objects&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;post&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;post&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;36 &lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;context&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;37 &lt;/span&gt;        &lt;span class=&quot;s2&quot;&gt;&amp;quot;post&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;post&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;38 &lt;/span&gt;        &lt;span class=&quot;s2&quot;&gt;&amp;quot;comments&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;comments&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;39 &lt;/span&gt;&lt;span class=&quot;hll&quot;&gt;        &lt;span class=&quot;s2&quot;&gt;&amp;quot;form&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;form&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;lineno&quot;&gt;40 &lt;/span&gt;    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;41 &lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;blog_detail.html&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;On &lt;strong&gt;line 24&lt;/strong&gt;, we create an instance of our form class. Don&amp;rsquo;t forget to import your form at the beginning of the file:&lt;/p&gt;
&lt;div class=&quot;highlight python&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CommentForm&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;We then go on to check if a &lt;code&gt;POST&lt;/code&gt; request has been received. If it has, then we create a new instance of our form, populated with the data entered into the form.&lt;/p&gt;
&lt;p&gt;The form is then validated using &lt;code&gt;is_valid()&lt;/code&gt;. If the form is valid, a new instance of &lt;code&gt;Comment&lt;/code&gt; is created. You can access the data from the form using &lt;code&gt;form.cleaned_data&lt;/code&gt;, which is a dictionary.&lt;/p&gt;
&lt;p&gt;They keys of the dictionary correspond to the form fields, so you can access the author using &lt;code&gt;form.cleaned_data[&#39;author&#39;]&lt;/code&gt;. Don&amp;rsquo;t forget to add the current post to the comment when you create it.&lt;/p&gt;
&lt;div class=&quot;alert alert-primary&quot; role=&quot;alert&quot;&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The life cycle of submitting a form can be a little complicated, so here&amp;rsquo;s an outline of how it works:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;When a user visits a page containing a form, they send a &lt;code&gt;GET&lt;/code&gt; request to the server. In this case, there&amp;rsquo;s no data entered in the form, so we just want to render the form and display it.&lt;/li&gt;
&lt;li&gt;When a user enters information and clicks the &lt;em&gt;Submit&lt;/em&gt; button, a &lt;code&gt;POST&lt;/code&gt; request, containing the data submitted with the form, is sent to the server. At this point, the data must be processed, and two things can happen:&lt;ul&gt;
&lt;li&gt;The form is valid, and the user is redirected to the next page.&lt;/li&gt;
&lt;li&gt;The form is invalid, and empty form is once again displayed. The user is back at step 1, and the process repeats.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;p&gt;The Django forms module will output some errors, which you can display to the user. This is beyond the scope of this tutorial, but you can read more about &lt;a href=&quot;https://docs.djangoproject.com/en/2.1/topics/forms/#rendering-form-error-messages&quot;&gt;rendering form error messages&lt;/a&gt; in the Django documentation.&lt;/p&gt;
&lt;p&gt;On &lt;strong&gt;line 33&lt;/strong&gt;, save the comment and go on to add the &lt;code&gt;form&lt;/code&gt; to the &lt;code&gt;context&lt;/code&gt; dictionary so you can access the form in the HTML template.&lt;/p&gt;
&lt;p&gt;The final step before you get to create the templates and actually see this blog up and running is to hook up the URLs. You&amp;rsquo;ll need create another &lt;code&gt;urls.py&lt;/code&gt; file inside &lt;code&gt;blog/&lt;/code&gt; and add the URLs for the three views:&lt;/p&gt;
&lt;div class=&quot;highlight python&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;django.urls&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;path&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;views&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;urlpatterns&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;views&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;blog_index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;blog_index&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&amp;lt;int:pk&amp;gt;/&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;views&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;blog_detail&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;blog_detail&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&amp;lt;category&amp;gt;/&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;views&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;blog_category&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;blog_category&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Once the blog-specific URLs are in place, you need to add them to the projects URL configuration using &lt;code&gt;include()&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight python&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;django.contrib&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;admin&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;django.urls&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;include&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;urlpatterns&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;admin/&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;admin&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;site&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;urls&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;projects/&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;include&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;projects.urls&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)),&lt;/span&gt;
&lt;span class=&quot;hll&quot;&gt;    &lt;span class=&quot;n&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;blog/&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;include&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;blog.urls&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)),&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;With this set up, all the blog URLs will be prefixed with &lt;code&gt;blog/&lt;/code&gt;, and you&amp;rsquo;ll have the following URL paths:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;localhost:8000/blog&lt;/code&gt;:&lt;/strong&gt; Blog index&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;localhost:8000/blog/1&lt;/code&gt;:&lt;/strong&gt; Blog detail view of blog with &lt;code&gt;pk=1&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;localhost:8000/blog/python&lt;/code&gt;:&lt;/strong&gt; Blog index view of all posts with category &lt;code&gt;python&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These URLs won&amp;rsquo;t work just yet as you still need to create the templates.&lt;/p&gt;
&lt;p&gt;In this section, you created all the views for your blog application. You learned how to use filters when making queries and how to create Django forms. It won&amp;rsquo;t be long now until you can see your blog app in action!&lt;/p&gt;
&lt;p&gt;As always, don&amp;rsquo;t forget that you can check out the &lt;a href=&quot;https://github.com/realpython/materials/tree/8ae8693470e7126a233f5d49685ad65bce3cb537/rp-portfolio&quot;&gt;source code&lt;/a&gt; for this section on GitHub.&lt;/p&gt;
&lt;h3 id=&quot;blog-app-templates&quot;&gt;Blog App: Templates&lt;/h3&gt;
&lt;p&gt;The final piece of our blog app is the templates. By the end of this section, you&amp;rsquo;ll have created a fully functioning blog.&lt;/p&gt;
&lt;p&gt;You&amp;rsquo;ll notice there are some bootstrap elements included in the templates to make the interface prettier. These aren&amp;rsquo;t the focus of the tutorial so I&amp;rsquo;ve glossed over what they do but do check out the &lt;a href=&quot;https://getbootstrap.com/docs/4.1/getting-started/introduction/&quot;&gt;Bootstrap docs&lt;/a&gt; to find out more.&lt;/p&gt;
&lt;p&gt;The first template you&amp;rsquo;ll create is for the blog index in a new file &lt;code&gt;blog/templates/blog_index.html&lt;/code&gt;. This will be very similar to the projects index view.&lt;/p&gt;
&lt;p&gt;You&amp;rsquo;ll use a for loop to loop over all the posts. For each post, you&amp;rsquo;ll display the title and a snippet of the body. As always, you&amp;rsquo;ll extend the base template &lt;code&gt;personal_porfolio/templates/base.html&lt;/code&gt;, which contains our navigation bar and some extra formatting:&lt;/p&gt;
&lt;div class=&quot;highlight htmldjango&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;lineno&quot;&gt; 1 &lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;base.html&amp;quot;&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 2 &lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;block&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;page_content&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 3 &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;col-md-8 offset-md-2&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 4 &lt;/span&gt;    &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;h1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;Blog Index&lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;h1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 5 &lt;/span&gt;    &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;hr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 6 &lt;/span&gt;    &lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;post&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;posts&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 7 &lt;/span&gt;    &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;h2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;url&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;blog_detail&amp;#39;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;post.pk&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;post.title&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;h2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 8 &lt;/span&gt;    &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;small&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 9 &lt;/span&gt;        &lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;post.created_on.date&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt; |&lt;span class=&quot;ni&quot;&gt;&amp;amp;nbsp;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;10 &lt;/span&gt;        Categories:&lt;span class=&quot;ni&quot;&gt;&amp;amp;nbsp;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;11 &lt;/span&gt;        &lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;category&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;post.categories.all&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;12 &lt;/span&gt;        &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;url&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;blog_category&amp;#39;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;category.name&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;13 &lt;/span&gt;            &lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;category.name&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;14 &lt;/span&gt;        &lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;ni&quot;&gt;&amp;amp;nbsp;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;15 &lt;/span&gt;        &lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;endfor&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;16 &lt;/span&gt;    &lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;small&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;17 &lt;/span&gt;    &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;post.body&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;slice&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;:&amp;quot;:400&amp;quot;&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt;...&lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;18 &lt;/span&gt;    &lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;endfor&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;19 &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;20 &lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;endblock&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;On &lt;strong&gt;line 7&lt;/strong&gt;, we have the post title, which is a hyperlink. The link is a Django link where we are pointing to the URL named &lt;code&gt;blog_detail&lt;/code&gt;, which takes an integer as its argument and should correspond to the &lt;code&gt;pk&lt;/code&gt; value of the post.&lt;/p&gt;
&lt;p&gt;Underneath the title, we&amp;rsquo;ll display the &lt;code&gt;created_on&lt;/code&gt; attribute of the post as well as its categories. On &lt;strong&gt;line 11&lt;/strong&gt;, we use another for loop to loop over all the categories assigned to the post.&lt;/p&gt;
&lt;p&gt;On &lt;strong&gt;line 17&lt;/strong&gt;, we use a &lt;strong&gt;template filter&lt;/strong&gt; &lt;a href=&quot;https://docs.djangoproject.com/en/2.1/ref/templates/builtins/#slice&quot;&gt;&lt;code&gt;slice&lt;/code&gt;&lt;/a&gt; to cut off the post body at 400 characters so that the blog index is more readable.&lt;/p&gt;
&lt;p&gt;Once that&amp;rsquo;s in place, you should be able to access this page by visiting &lt;code&gt;localhost:8000/blog&lt;/code&gt;:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://files.realpython.com/media/Screenshot_2018-12-17_at_23.50.45.fedcaa17e99d.png&quot; target=&quot;_blank&quot;&gt;&lt;img class=&quot;img-fluid mx-auto d-block &quot; src=&quot;https://files.realpython.com/media/Screenshot_2018-12-17_at_23.50.45.fedcaa17e99d.png&quot; width=&quot;2784&quot; height=&quot;1628&quot; srcset=&quot;https://robocrop.realpython.net/?url=https%3A//files.realpython.com/media/Screenshot_2018-12-17_at_23.50.45.fedcaa17e99d.png&amp;amp;w=696&amp;amp;sig=b6b77490140a81ab853e03e32c26e3288e5ab0c4 696w, https://robocrop.realpython.net/?url=https%3A//files.realpython.com/media/Screenshot_2018-12-17_at_23.50.45.fedcaa17e99d.png&amp;amp;w=1392&amp;amp;sig=8f94d6fc2af62032514ef52372729769fd55f2c9 1392w, https://files.realpython.com/media/Screenshot_2018-12-17_at_23.50.45.fedcaa17e99d.png 2784w&quot; sizes=&quot;75vw&quot; alt=&quot;Blog Index View&quot;/&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Next, create another HTML file &lt;code&gt;blog/templates/blog_category.html&lt;/code&gt; where your &lt;code&gt;blog_category&lt;/code&gt; template will live. This should be identical to &lt;code&gt;blog_index.html&lt;/code&gt;, except with the category name inside the &lt;code&gt;h1&lt;/code&gt; tag instead of &lt;code&gt;Blog Index&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight htmldjango&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;lineno&quot;&gt; 1 &lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;base.html&amp;quot;&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 2 &lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;block&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;page_content&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 3 &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;col-md-8 offset-md-2&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 4 &lt;/span&gt;&lt;span class=&quot;hll&quot;&gt;    &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;h1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;category&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;title&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;h1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;lineno&quot;&gt; 5 &lt;/span&gt;    &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;hr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 6 &lt;/span&gt;    &lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;post&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;posts&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 7 &lt;/span&gt;        &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;h2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;url&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;blog_detail&amp;#39;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;post.pk&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;post.title&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;h2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 8 &lt;/span&gt;        &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;small&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 9 &lt;/span&gt;            &lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;post.created_on.date&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt; |&lt;span class=&quot;ni&quot;&gt;&amp;amp;nbsp;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;10 &lt;/span&gt;            Categories:&lt;span class=&quot;ni&quot;&gt;&amp;amp;nbsp;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;11 &lt;/span&gt;            &lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;category&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;post.categories.all&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;12 &lt;/span&gt;            &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;url&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;blog_category&amp;#39;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;category.name&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;13 &lt;/span&gt;                &lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;category.name&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;14 &lt;/span&gt;            &lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;ni&quot;&gt;&amp;amp;nbsp;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;15 &lt;/span&gt;            &lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;endfor&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;16 &lt;/span&gt;        &lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;small&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;17 &lt;/span&gt;        &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;post.body&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;slice&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;:&amp;quot;:400&amp;quot;&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt;...&lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;18 &lt;/span&gt;    &lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;endfor&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;19 &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;20 &lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;endblock&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Most of this template is identical to the previous template. The only difference is on &lt;strong&gt;line 4&lt;/strong&gt;, where we use another Django template filter &lt;a href=&quot;https://docs.djangoproject.com/en/2.1/ref/templates/builtins/#title&quot;&gt;&lt;code&gt;title&lt;/code&gt;&lt;/a&gt;. This applies titlecase to the string and makes words start with an uppercase character.&lt;/p&gt;
&lt;p&gt;With that template finished, you&amp;rsquo;ll be able to access your category view. If you defined a category named &lt;code&gt;python&lt;/code&gt;, you should be able to visit &lt;code&gt;localhost:8000/blog/python&lt;/code&gt; and see all the posts with that category:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://files.realpython.com/media/Screenshot_2018-12-17_at_23.50.51.08dadaa185fc.png&quot; target=&quot;_blank&quot;&gt;&lt;img class=&quot;img-fluid mx-auto d-block &quot; src=&quot;https://files.realpython.com/media/Screenshot_2018-12-17_at_23.50.51.08dadaa185fc.png&quot; width=&quot;2784&quot; height=&quot;1628&quot; srcset=&quot;https://robocrop.realpython.net/?url=https%3A//files.realpython.com/media/Screenshot_2018-12-17_at_23.50.51.08dadaa185fc.png&amp;amp;w=696&amp;amp;sig=ba04bfb8c05fe5f7aed0aad6708a93b23286ccc7 696w, https://robocrop.realpython.net/?url=https%3A//files.realpython.com/media/Screenshot_2018-12-17_at_23.50.51.08dadaa185fc.png&amp;amp;w=1392&amp;amp;sig=79cb0ff0b706773f0b4e2d542b30437ce91e2824 1392w, https://files.realpython.com/media/Screenshot_2018-12-17_at_23.50.51.08dadaa185fc.png 2784w&quot; sizes=&quot;75vw&quot; alt=&quot;Blog Category View&quot;/&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The last template to create is the &lt;code&gt;post_detail&lt;/code&gt; template. In this template, you&amp;rsquo;ll display the title and full body of a post.&lt;/p&gt;
&lt;p&gt;Between the title and the body of the post, you&amp;rsquo;ll display the date the post was created and any categories. Underneath that, you&amp;rsquo;ll include a comments form so users can add a new comment. Under this, there will be a list of comments that have already been left:&lt;/p&gt;
&lt;div class=&quot;highlight htmldjango&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;lineno&quot;&gt; 1 &lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;base.html&amp;quot;&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 2 &lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;block&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;page_content&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 3 &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;col-md-8 offset-md-2&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 4 &lt;/span&gt;    &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;h1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;post.title&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;h1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 5 &lt;/span&gt;    &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;small&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 6 &lt;/span&gt;        &lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;post.created_on.date&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt; |&lt;span class=&quot;ni&quot;&gt;&amp;amp;nbsp;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 7 &lt;/span&gt;        Categories:&lt;span class=&quot;ni&quot;&gt;&amp;amp;nbsp;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 8 &lt;/span&gt;        &lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;category&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;post.categories.all&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 9 &lt;/span&gt;        &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;url&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;blog_category&amp;#39;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;category.name&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;10 &lt;/span&gt;            &lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;category.name&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;11 &lt;/span&gt;        &lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;ni&quot;&gt;&amp;amp;nbsp;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;12 &lt;/span&gt;        &lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;endfor&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;13 &lt;/span&gt;    &lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;small&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;14 &lt;/span&gt;    &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;post.body&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;linebreaks&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;15 &lt;/span&gt;    &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;h3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;Leave a comment:&lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;h3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;16 &lt;/span&gt;    &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;form&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;/blog/&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;post.pk&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;/&amp;quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;method&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;post&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;17 &lt;/span&gt;        &lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;csrf_token&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;18 &lt;/span&gt;        &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;form-group&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;19 &lt;/span&gt;            &lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;form.author&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;20 &lt;/span&gt;        &lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;21 &lt;/span&gt;        &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;form-group&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;22 &lt;/span&gt;            &lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;form.body&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;23 &lt;/span&gt;        &lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;24 &lt;/span&gt;        &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;button&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;submit&amp;quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;btn btn-primary&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;Submit&lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;button&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;25 &lt;/span&gt;    &lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;form&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;26 &lt;/span&gt;    &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;h3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;Comments:&lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;h3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;27 &lt;/span&gt;    &lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;comment&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;comments&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;28 &lt;/span&gt;    &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;29 &lt;/span&gt;        On &lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;comment.created_on.date&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt;&lt;span class=&quot;ni&quot;&gt;&amp;amp;nbsp;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;30 &lt;/span&gt;        &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;comment.author&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; wrote:
&lt;span class=&quot;lineno&quot;&gt;31 &lt;/span&gt;    &lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;32 &lt;/span&gt;    &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;comment.body&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;33 &lt;/span&gt;    &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;hr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;34 &lt;/span&gt;    &lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;endfor&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;35 &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;36 &lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;endblock&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The first few lines of the template in which we display the post title, date, and categories is the same logic as for the previous templates. This time, when rendering the post body, use a &lt;a href=&quot;https://docs.djangoproject.com/en/2.1/ref/templates/builtins/#linebreaks&quot;&gt;&lt;code&gt;linebreaks&lt;/code&gt;&lt;/a&gt; template filter. This tag registers line breaks as new paragraphs, so the body doesn&amp;rsquo;t appear as one long block of text.&lt;/p&gt;
&lt;p&gt;Underneath the post, on &lt;strong&gt;line 16&lt;/strong&gt;, you&amp;rsquo;ll display your form. The form action points to the URL path of the page to which you&amp;rsquo;re sending the &lt;code&gt;POST&lt;/code&gt; request to. In this case, it&amp;rsquo;s the same as the page that is currently being visited. You then add a &lt;code&gt;csrf_token&lt;/code&gt;, which provides security and renders the body and author fields of the form, followed by a submit button.&lt;/p&gt;
&lt;p&gt;To get the bootstrap styling on the author and body fields, you need to add the &lt;code&gt;form-control&lt;/code&gt; class to the text inputs.&lt;/p&gt;
&lt;p&gt;Because Django renders the inputs for you when you include &lt;code&gt;{{ form.body }}&lt;/code&gt; and &lt;code&gt;{{ form.author }}&lt;/code&gt;, you can&amp;rsquo;t add these classes in the template. That&amp;rsquo;s why you added the attributes to the form widgets in the previous section.&lt;/p&gt;
&lt;p&gt;Underneath the form, there&amp;rsquo;s another for loop that loops over all the comments on the given post. The comments, &lt;code&gt;body&lt;/code&gt;, &lt;code&gt;author&lt;/code&gt;, and &lt;code&gt;created_on&lt;/code&gt; attributes are all displayed.&lt;/p&gt;
&lt;p&gt;Once that template is in place, you should be able to visit &lt;code&gt;localhost:8000/blog/1&lt;/code&gt; and view your first post:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://files.realpython.com/media/Screenshot_2018-12-17_at_23.51.17.8849893e9b69.png&quot; target=&quot;_blank&quot;&gt;&lt;img class=&quot;img-fluid mx-auto d-block &quot; src=&quot;https://files.realpython.com/media/Screenshot_2018-12-17_at_23.51.17.8849893e9b69.png&quot; width=&quot;2770&quot; height=&quot;2046&quot; srcset=&quot;https://robocrop.realpython.net/?url=https%3A//files.realpython.com/media/Screenshot_2018-12-17_at_23.51.17.8849893e9b69.png&amp;amp;w=692&amp;amp;sig=84cd5d93b54a6af67a8e0fa6fe041ff71685e60c 692w, https://robocrop.realpython.net/?url=https%3A//files.realpython.com/media/Screenshot_2018-12-17_at_23.51.17.8849893e9b69.png&amp;amp;w=1385&amp;amp;sig=5e31cb4041dccc36447872e5a5528f8afc90b276 1385w, https://files.realpython.com/media/Screenshot_2018-12-17_at_23.51.17.8849893e9b69.png 2770w&quot; sizes=&quot;75vw&quot; alt=&quot;Blog Detail View&quot;/&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;You should also be able to access the post detail pages by clicking on their title in the &lt;code&gt;blog_index&lt;/code&gt; view.&lt;/p&gt;
&lt;p&gt;The final finishing touch is to add a link to the &lt;code&gt;blog_index&lt;/code&gt; to the navigation bar in &lt;code&gt;base.html&lt;/code&gt;. This way, when you click on &lt;em&gt;Blog&lt;/em&gt; in the navigation bar, you&amp;rsquo;ll be able to visit the blog. Check out &lt;a href=&quot;https://github.com/realpython/materials/blob/4dd5d79634efbffeb8999052a9e94b3dba4b25ba/rp-portfolio/personal_portfolio/templates/base.html#L16&quot;&gt;the updates&lt;/a&gt; to &lt;code&gt;base.html&lt;/code&gt; in the source code to see how to add that link.&lt;/p&gt;
&lt;p&gt;With that now in place, your personal portfolio site is complete, and you&amp;rsquo;ve created your first Django site. The final version of the &lt;a href=&quot;https://github.com/realpython/materials/tree/4dd5d79634efbffeb8999052a9e94b3dba4b25ba/rp-portfolio&quot;&gt;source code&lt;/a&gt; containing all the features can be found on GitHub, so check it out! Click around the site a bit to see all the functionality and try leaving some comments on your posts!&lt;/p&gt;
&lt;p&gt;You may find a few things here and there that you think need polishing. Go ahead and tidy them up. The best way to learn more about this web framework is through practice, so try to extend this project and make it even better! If you&amp;rsquo;re not sure where to start, I&amp;rsquo;ve left a few ideas for you in the conclusion below!&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Congratulations, you&amp;rsquo;ve reached the end of the tutorial! We&amp;rsquo;ve covered a lot, so make sure to keep practicing and building. The more you build the easier it will become and the less you&amp;rsquo;ll have to refer back to this article or the &lt;a href=&quot;https://docs.djangoproject.com/en/2.1/&quot;&gt;documentation&lt;/a&gt;. You&amp;rsquo;ll be building sophisticated web applications in no time.&lt;/p&gt;
&lt;p&gt;In this tutorial you&amp;rsquo;ve seen:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;How to create Django &lt;strong&gt;projects&lt;/strong&gt; and &lt;strong&gt;apps&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;How to add web pages with &lt;strong&gt;views&lt;/strong&gt; and &lt;strong&gt;templates&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;How to get user input with &lt;strong&gt;forms&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;How to hook your views and templates up with &lt;strong&gt;URL&lt;/strong&gt; configurations&lt;/li&gt;
&lt;li&gt;How to add data to your site using relational databases with Django&amp;rsquo;s &lt;strong&gt;Object Relational Mapper&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;How to use the &lt;strong&gt;Django Admin&lt;/strong&gt; to manage your models&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In addition, you&amp;rsquo;ve learned about the MVT structure of Django web applications and why Django is such a good choice for web development.&lt;/p&gt;
&lt;p&gt;If you want to learn more about Django, do check out the &lt;a href=&quot;https://docs.djangoproject.com/en/2.1/&quot;&gt;documentation&lt;/a&gt; and make sure to stay tuned for Part 2 of this series!&lt;/p&gt;
        &lt;hr /&gt;
        &lt;p&gt;&lt;em&gt;[ Improve Your Python With 🐍 Python Tricks 💌 – Get a short &amp;amp; sweet Python Trick delivered to your inbox every couple of days. &lt;a href=&quot;https://realpython.com/python-tricks/?utm_source=realpython&amp;amp;utm_medium=rss&amp;amp;utm_campaign=footer&quot;&gt;&amp;gt;&amp;gt; Click here to learn more and see examples&lt;/a&gt; ]&lt;/em&gt;&lt;/p&gt;
      </content>
    </entry>
  
    <entry>
      <title>Working With JSON Data in Python</title>
      <id>https://realpython.com/courses/working-json-data-python/</id>
      <link href="https://realpython.com/courses/working-json-data-python/"/>
      <updated>2019-03-28T14:00:00+00:00</updated>
      <summary>Learn how to work with Python&#39;s built-in &quot;json&quot; module to serialize the data in your programs into JSON format. Then, you&#39;ll deserialize some JSON from an online API and convert it into Python objects.</summary>
      <content type="html">
        &lt;p&gt;JSON is a lightweight data-interchange format. It allows us to represent the objects in our Python programs as human-readable text that can be sent over the internet. Lots of APIs and databases use JSON for communication.&lt;/p&gt;
&lt;p&gt;You&amp;rsquo;ll learn how to work with Python&amp;rsquo;s built-in &lt;code&gt;json&lt;/code&gt; module to serialize the data in your programs into JSON format. Then, you&amp;rsquo;ll deserialize some JSON from an online API and convert it into Python objects.&lt;/p&gt;
        &lt;hr /&gt;
        &lt;p&gt;&lt;em&gt;[ Improve Your Python With 🐍 Python Tricks 💌 – Get a short &amp;amp; sweet Python Trick delivered to your inbox every couple of days. &lt;a href=&quot;https://realpython.com/python-tricks/?utm_source=realpython&amp;amp;utm_medium=rss&amp;amp;utm_campaign=footer&quot;&gt;&amp;gt;&amp;gt; Click here to learn more and see examples&lt;/a&gt; ]&lt;/em&gt;&lt;/p&gt;
      </content>
    </entry>
  
    <entry>
      <title>How to Stand Out in a Python Coding Interview</title>
      <id>https://realpython.com/python-coding-interview-tips/</id>
      <link href="https://realpython.com/python-coding-interview-tips/"/>
      <updated>2019-03-27T14:00:00+00:00</updated>
      <summary>In this step-by-step tutorial, you&#39;ll learn how to take your Python coding interview skills to the next level and use Python&#39;s built-in functions and modules to solve problems faster and more easily.</summary>
      <content type="html">
        &lt;p&gt;You&amp;rsquo;ve made it past the phone call with the recruiter, and now it&amp;rsquo;s time to show that you know how to solve problems with actual code. Whether it&amp;rsquo;s a HackerRank exercise, a take-home assignment, or an onsite whiteboard interview, this is your moment to prove your coding interview skills.&lt;/p&gt;
&lt;p&gt;But interviews aren&amp;rsquo;t just about solving problems: they&amp;rsquo;re also about showing that you can write clean production code. This means that you have a deep knowledge of Python&amp;rsquo;s built-in functionality and libraries. This knowledge shows companies that you can move quickly and won&amp;rsquo;t duplicate functionality that comes with the language just because you don&amp;rsquo;t know it exists.&lt;/p&gt;
&lt;p&gt;At &lt;em&gt;Real Python&lt;/em&gt;, we&amp;rsquo;ve put our heads together and discussed what tools we&amp;rsquo;re always impressed to see in coding interviews. This article will walk you through the best of that functionality, starting with Python built-ins, then Python&amp;rsquo;s native support for data structures, and finally Python&amp;rsquo;s powerful (and often underappreciated) standard library.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;In this article, you&amp;rsquo;ll learn how to:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Use &lt;code&gt;enumerate()&lt;/code&gt; to iterate over both indices and values&lt;/li&gt;
&lt;li&gt;Debug problematic code with &lt;code&gt;breakpoint()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Format strings effectively with f-strings&lt;/li&gt;
&lt;li&gt;Sort lists with custom arguments&lt;/li&gt;
&lt;li&gt;Use generators instead of list comprehensions to conserve memory&lt;/li&gt;
&lt;li&gt;Define default values when looking up dictionary keys&lt;/li&gt;
&lt;li&gt;Count hashable objects with the &lt;code&gt;collections.Counter&lt;/code&gt; class&lt;/li&gt;
&lt;li&gt;Use the standard library to get lists of permutations and combinations&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;alert alert-warning&quot; role=&quot;alert&quot;&gt;&lt;p&gt;&lt;strong&gt;Free Bonus:&lt;/strong&gt; &lt;a href=&quot;&quot; class=&quot;alert-link&quot; data-toggle=&quot;modal&quot; data-target=&quot;#modal-python-mastery-course&quot; data-focus=&quot;false&quot;&gt;5 Thoughts On Python Mastery&lt;/a&gt;, a free course for Python developers that shows you the roadmap and the mindset you&#39;ll need to take your Python skills to the next level.&lt;/p&gt;&lt;/div&gt;

&lt;h2 id=&quot;select-the-right-built-in-function-for-the-job&quot;&gt;Select the Right Built-In Function for the Job&lt;/h2&gt;
&lt;p&gt;Python has a large standard library but only a small library of &lt;a href=&quot;https://docs.python.org/library/functions.html&quot;&gt;built-in functions&lt;/a&gt;, which are always available and don&amp;rsquo;t need to be imported. It&amp;rsquo;s worth going through each one, but until you get the chance to do so, here are a few built-in functions worth understanding how to use, and in the case of some of them, what alternatives to use instead.&lt;/p&gt;
&lt;h3 id=&quot;iterate-with-enumerate-instead-of-range&quot;&gt;Iterate With &lt;code&gt;enumerate()&lt;/code&gt; Instead of &lt;code&gt;range()&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;This scenario might come up more than any other in coding interviews: you have a list of elements, and you need to iterate over the list with access to both the indices and the values.&lt;/p&gt;
&lt;p&gt;There&amp;rsquo;s a classic coding interview question named FizzBuzz that can be solved by iterating over both indices and values. In FizzBuzz, you are given a list of integers. Your task is to do the following:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Replace all integers that are evenly divisible by &lt;code&gt;3&lt;/code&gt; with &lt;code&gt;&quot;fizz&quot;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Replace all integers divisible by &lt;code&gt;5&lt;/code&gt; with &lt;code&gt;&quot;buzz&quot;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Replace all integers divisible by both &lt;code&gt;3&lt;/code&gt; and &lt;code&gt;5&lt;/code&gt; with &lt;code&gt;&quot;fizzbuzz&quot;&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Often, developers will solve this problem with &lt;code&gt;range()&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight python pycon&quot;&gt;&lt;span class=&quot;repl-toggle&quot; title=&quot;Toggle REPL prompts and output&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;numbers&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;45&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;22&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;14&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;65&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;97&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;72&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;range&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;numbers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)):&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;... &lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;numbers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;and&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;numbers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;... &lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;numbers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;fizzbuzz&amp;#39;&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;... &lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;elif&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;numbers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;... &lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;numbers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;fizz&amp;#39;&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;... &lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;elif&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;numbers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;... &lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;numbers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;buzz&amp;#39;&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;...&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;numbers&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;[&amp;#39;fizzbuzz&amp;#39;, 22, 14, &amp;#39;buzz&amp;#39;, 97, &amp;#39;fizz&amp;#39;]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Range allows you to access the elements of &lt;code&gt;numbers&lt;/code&gt; by index and is a useful tool &lt;a href=&quot;https://realpython.com/python-range/&quot;&gt;for some situations&lt;/a&gt;. But in this case, where you want to get each element&amp;rsquo;s index and value at the same time, a more elegant solution uses &lt;code&gt;enumerate()&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight python pycon&quot;&gt;&lt;span class=&quot;repl-toggle&quot; title=&quot;Toggle REPL prompts and output&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;numbers&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;45&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;22&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;14&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;65&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;97&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;72&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;num&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;enumerate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;numbers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;... &lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;num&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;and&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;num&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;... &lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;numbers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;fizzbuzz&amp;#39;&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;... &lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;elif&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;num&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;... &lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;numbers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;fizz&amp;#39;&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;... &lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;elif&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;num&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;... &lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;numbers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;buzz&amp;#39;&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;...&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;numbers&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;[&amp;#39;fizzbuzz&amp;#39;, 22, 14, &amp;#39;buzz&amp;#39;, 97, &amp;#39;fizz&amp;#39;]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;For each element, &lt;code&gt;enumerate()&lt;/code&gt; returns a counter and the element value. The counter defaults to &lt;code&gt;0&lt;/code&gt;, which conveniently is also the element&amp;rsquo;s index. Don&amp;rsquo;t want to start your count at &lt;code&gt;0&lt;/code&gt;? Just use the optional &lt;code&gt;start&lt;/code&gt; parameter to set an offset:&lt;/p&gt;
&lt;div class=&quot;highlight python pycon&quot;&gt;&lt;span class=&quot;repl-toggle&quot; title=&quot;Toggle REPL prompts and output&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;numbers&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;45&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;22&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;14&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;65&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;97&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;72&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;num&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;enumerate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;numbers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;start&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;52&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;... &lt;/span&gt;    &lt;span class=&quot;nb&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;num&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;...&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;52 45&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;53 22&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;54 14&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;55 65&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;56 97&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;57 72&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;By using the &lt;code&gt;start&lt;/code&gt; parameter, we access all of the same elements, starting with the first index, but now our count starts from the specified integer value.&lt;/p&gt;
&lt;h3 id=&quot;use-list-comprehensions-instead-of-map-and-filter&quot;&gt;Use List Comprehensions Instead of &lt;code&gt;map()&lt;/code&gt; and &lt;code&gt;filter()&lt;/code&gt;&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;ldquo;I think dropping filter() and map() is pretty uncontroversial[.]&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&amp;mdash; &lt;em&gt;Guido van Rossum, Python&amp;rsquo;s creator&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;He may have been wrong about it being uncontroversial, but Guido had good reasons for wanting to remove &lt;code&gt;map()&lt;/code&gt; and &lt;code&gt;filter()&lt;/code&gt; from Python. One reason is that Python supports list comprehensions, which are often easier to read and support the same functionality as &lt;code&gt;map()&lt;/code&gt; and &lt;code&gt;filter()&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s first take a look at how we&amp;rsquo;d structure a call to &lt;code&gt;map()&lt;/code&gt; and the equivalent list comprehension:&lt;/p&gt;
&lt;div class=&quot;highlight python pycon&quot;&gt;&lt;span class=&quot;repl-toggle&quot; title=&quot;Toggle REPL prompts and output&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;numbers&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;9&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;square&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;... &lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;...&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;list&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;square&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;numbers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;[16, 4, 1, 36, 81, 49]&lt;/span&gt;

&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;square&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;numbers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;[16, 4, 1, 36, 81, 49]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Both approaches, using &lt;code&gt;map()&lt;/code&gt; and the list comprehension, return the same values, but the list comprehension is easier to read and understand.&lt;/p&gt;
&lt;p&gt;Now we can do the same thing for the &lt;code&gt;filter()&lt;/code&gt; and its equivalent list comprehension:&lt;/p&gt;
&lt;div class=&quot;highlight python pycon&quot;&gt;&lt;span class=&quot;repl-toggle&quot; title=&quot;Toggle REPL prompts and output&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;is_odd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;... &lt;/span&gt;   &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;bool&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;...&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;list&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;is_odd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;numbers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;[1, 9, 7]&lt;/span&gt;

&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;numbers&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;is_odd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)]&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;[1, 9, 7]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Like we saw with &lt;code&gt;map()&lt;/code&gt;, the &lt;code&gt;filter()&lt;/code&gt; and list comprehension approaches return the same value, but the list comprehension is easier to follow.&lt;/p&gt;
&lt;p&gt;Developers who come from other languages may disagree that list comprehensions are easier to read than &lt;code&gt;map()&lt;/code&gt; and &lt;code&gt;filter()&lt;/code&gt;, but in my experience beginners are able to pick up list comprehensions much more intuitively.&lt;/p&gt;
&lt;p&gt;Either way, you&amp;rsquo;ll rarely go wrong using list comprehensions in a coding interview, as it will communicate that you know what&amp;rsquo;s most common in Python.&lt;/p&gt;
&lt;h3 id=&quot;debug-with-breakpoint-instead-of-print&quot;&gt;Debug With &lt;code&gt;breakpoint()&lt;/code&gt; Instead of &lt;code&gt;print()&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;You may have debugged a small problem by adding &lt;code&gt;print()&lt;/code&gt; to your code and seeing what was printed out. This approach works well at first but quickly becomes cumbersome. Plus, in a coding interview setting, you hardly want &lt;code&gt;print()&lt;/code&gt; calls peppered throughout your code.&lt;/p&gt;
&lt;p&gt;Instead, you should be using a debugger. For non-trivial bugs, it&amp;rsquo;s almost always faster than using &lt;code&gt;print()&lt;/code&gt;, and given that debugging is a big part of writing software, it shows that you know how to use tools that will let you develop quickly on the job.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re using Python 3.7, you don&amp;rsquo;t need to import anything and can just call &lt;a href=&quot;https://realpython.com/python37-new-features/#the-breakpoint-built-in&quot;&gt;&lt;code&gt;breakpoint()&lt;/code&gt;&lt;/a&gt; at the location in your code where you&amp;rsquo;d like to drop into the debugger:&lt;/p&gt;
&lt;div class=&quot;highlight python&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;# Some complicated code with bugs&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;breakpoint&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Calling &lt;code&gt;breakpoint()&lt;/code&gt; will put you into &lt;a href=&quot;https://realpython.com/python-debugging-pdb/&quot;&gt;&lt;code&gt;pdb&lt;/code&gt;&lt;/a&gt;, which is the default Python debugger. On Python 3.6 and older, you can do the same by importing &lt;code&gt;pdb&lt;/code&gt; explicitly:&lt;/p&gt;
&lt;div class=&quot;highlight python&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;pdb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pdb&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;set_trace&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Like &lt;code&gt;breakpoint()&lt;/code&gt;, &lt;code&gt;pdb.set_trace()&lt;/code&gt; will put you into the &lt;code&gt;pdb&lt;/code&gt; debugger. It&amp;rsquo;s just not quite as clean and is a tad more to remember.&lt;/p&gt;
&lt;p&gt;There are other debuggers available that you may want to try, but &lt;code&gt;pdb&lt;/code&gt; is part of the standard library, so it&amp;rsquo;s always available. Whatever debugger you prefer, it&amp;rsquo;s worth trying them out to get used to the workflow before you&amp;rsquo;re in a coding interview setting.&lt;/p&gt;
&lt;h3 id=&quot;format-strings-with-f-strings&quot;&gt;Format strings With f-Strings&lt;/h3&gt;
&lt;p&gt;Python has a lot of different ways to handle string formatting, and it can be tricky to know what to use. In fact, we tackle formatting in depth in two separate articles: one about &lt;a href=&quot;https://realpython.com/python-string-formatting/&quot;&gt;string formatting in general&lt;/a&gt; and one specifically &lt;a href=&quot;https://realpython.com/python-f-strings/&quot;&gt;focused on f-strings&lt;/a&gt;. In a coding interview, where you&amp;rsquo;re (hopefully) using Python 3.6+, the suggested formatting approach is Python&amp;rsquo;s f-strings.&lt;/p&gt;
&lt;p&gt;f-strings support use of the &lt;a href=&quot;https://docs.python.org/3/library/string.html#format-specification-mini-language&quot;&gt;string formatting mini-language&lt;/a&gt;, as well as powerful string interpolation. These features allow you to add variables or even valid Python expressions and have them evaluated at runtime before being added to the string:&lt;/p&gt;
&lt;div class=&quot;highlight python pycon&quot;&gt;&lt;span class=&quot;repl-toggle&quot; title=&quot;Toggle REPL prompts and output&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;get_name_and_decades&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;age&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;... &lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;My name is &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{name}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; and I&amp;#39;m {age / 10:.5f} decades old.&amp;quot;&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;...&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get_name_and_decades&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;Maria&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;31&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;My name is Maria and I&amp;#39;m 3.10000 decades old.&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The f-string allows you to put &lt;code&gt;Maria&lt;/code&gt; into the string and add her age with the desired formatting in one succinct operation.&lt;/p&gt;
&lt;p&gt;The one risk to be aware of is that if you&amp;rsquo;re outputting user-generated values, then that can introduce security risks, in which case &lt;a href=&quot;https://realpython.com/python-string-formatting/#4-template-strings-standard-library&quot;&gt;Template Strings&lt;/a&gt; may be a safer option.&lt;/p&gt;
&lt;h3 id=&quot;sort-complex-lists-with-sorted&quot;&gt;Sort Complex Lists With &lt;code&gt;sorted()&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;Plenty of coding interview questions require some kind of sorting, and there are multiple valid ways you can sort items. Unless the interviewer wants you to implement your own sorting algorithm, it&amp;rsquo;s usually best to use &lt;code&gt;sorted()&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;You&amp;rsquo;ve probably seen the most simple uses of sorting, such as sorting lists of numbers or strings in ascending or descending order:&lt;/p&gt;
&lt;div class=&quot;highlight python pycon&quot;&gt;&lt;span class=&quot;repl-toggle&quot; title=&quot;Toggle REPL prompts and output&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sorted&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;[1, 2, 3, 4, 5, 6, 7]&lt;/span&gt;

&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sorted&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;cat&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;dog&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;cheetah&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;rhino&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;bear&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;reverse&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;[&amp;#39;rhino&amp;#39;, &amp;#39;dog&amp;#39;, &amp;#39;cheetah&amp;#39;, &amp;#39;cat&amp;#39;, &amp;#39;bear]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;By default, &lt;code&gt;sorted()&lt;/code&gt; has sorted the input in ascending order, and the &lt;code&gt;reverse&lt;/code&gt; keyword argument causes it to sort in descending order.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s worth knowing about the optional keyword argument &lt;code&gt;key&lt;/code&gt; that lets you specify a function that will be called on every element prior to sorting. Adding a function allows custom sorting rules, which are especially helpful if you want to sort more complex data types:&lt;/p&gt;
&lt;div class=&quot;highlight python pycon&quot;&gt;&lt;span class=&quot;repl-toggle&quot; title=&quot;Toggle REPL prompts and output&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;animals&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;... &lt;/span&gt;    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;type&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;penguin&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;name&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;Stephanie&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;age&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;... &lt;/span&gt;    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;type&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;elephant&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;name&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;Devon&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;age&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;... &lt;/span&gt;    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;type&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;puma&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;name&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;Moe&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;age&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;... &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sorted&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;animals&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;lambda&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;animal&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;animal&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;age&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;[&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;    {&amp;#39;type&amp;#39;: &amp;#39;elephant&amp;#39;, &amp;#39;name&amp;#39;: &amp;#39;Devon&amp;#39;, &amp;#39;age&amp;#39;: 3},&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;    {&amp;#39;type&amp;#39;: &amp;#39;puma&amp;#39;, &amp;#39;name&amp;#39;: &amp;#39;Moe&amp;#39;, &amp;#39;age&amp;#39;: 5},&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;    {&amp;#39;type&amp;#39;: &amp;#39;penguin&amp;#39;, &amp;#39;name&amp;#39;: &amp;#39;Stephanie, &amp;#39;age&amp;#39;: 8},&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;By passing in a &lt;a href=&quot;https://docs.python.org/3/tutorial/controlflow.html#lambda-expressions&quot;&gt;lambda function&lt;/a&gt; that returns each element&amp;rsquo;s age, you can easily sort a list of dictionaries by a single value of each of those dictionaries. In this case, the dictionary is now sorted in ascending order by age.&lt;/p&gt;
&lt;h2 id=&quot;leverage-data-structures-effectively&quot;&gt;Leverage Data Structures Effectively&lt;/h2&gt;
&lt;p&gt;Algorithms get a lot of attention in coding interviews, but data structures are arguably even more important. In a coding interviewing context, picking the right data structure can have a major impact on performance.&lt;/p&gt;
&lt;p&gt;Beyond theoretical data structures, Python has powerful and convenient functionality built into its standard data structure implementations. These data structures are incredibly useful in coding interviews because they give you lots of functionality by default and let you focus your time on other parts of the problem.&lt;/p&gt;
&lt;h3 id=&quot;store-unique-values-with-sets&quot;&gt;Store Unique Values With Sets&lt;/h3&gt;
&lt;p&gt;You&amp;rsquo;ll often need to remove duplicate elements from an existing dataset. New developers will sometimes do so with lists when they should be using sets, which enforce the uniqueness of all elements.&lt;/p&gt;
&lt;p&gt;Pretend you have a function named &lt;code&gt;get_random_word()&lt;/code&gt;. It will always return a random selection from a small set of words:&lt;/p&gt;
&lt;div class=&quot;highlight python pycon&quot;&gt;&lt;span class=&quot;repl-toggle&quot; title=&quot;Toggle REPL prompts and output&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;random&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;all_words&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;all the words in the world&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;get_random_word&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;... &lt;/span&gt;   &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;random&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;choice&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;all_words&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You&amp;rsquo;re supposed to call &lt;code&gt;get_random_word()&lt;/code&gt; repeatedly to get 1000 random words and then return a data structure containing every unique word. Here are two common, suboptimal approaches and one good approach.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Bad Approach&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;get_unique_words()&lt;/code&gt; stores values in a list then converts the list into a set:&lt;/p&gt;
&lt;div class=&quot;highlight python pycon&quot;&gt;&lt;span class=&quot;repl-toggle&quot; title=&quot;Toggle REPL prompts and output&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;get_unique_words&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;... &lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;words&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;... &lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;range&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;... &lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;words&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get_random_word&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;... &lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;words&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get_unique_words&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;{&amp;#39;world&amp;#39;, &amp;#39;all&amp;#39;, &amp;#39;the&amp;#39;, &amp;#39;words&amp;#39;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This approach isn&amp;rsquo;t terrible, but it unnecessarily creates a list and then converts it to a set. Interviewers almost always notice (and ask about) this type of design choice.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Worse Approach&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;To avoid converting from a list to a set, you now store values in a list without using any other data structures. You then test for uniqueness by comparing new values with all elements currently in the list:&lt;/p&gt;
&lt;div class=&quot;highlight python pycon&quot;&gt;&lt;span class=&quot;repl-toggle&quot; title=&quot;Toggle REPL prompts and output&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;get_unique_words&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;... &lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;words&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;... &lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;range&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;... &lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;word&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;get_random_word&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;... &lt;/span&gt;        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;word&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;words&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;... &lt;/span&gt;            &lt;span class=&quot;n&quot;&gt;words&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;word&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;... &lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;words&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get_unique_words&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;[&amp;#39;world&amp;#39;, &amp;#39;all&amp;#39;, &amp;#39;the&amp;#39;, &amp;#39;words&amp;#39;]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This is worse than the first approach, because you have to compare every new word against every word already in the list. That means that as the number of words grows, the number of lookups grows quadratically. In other words, the time complexity grows on the order of O(N²).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Good Approach&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Now, you skip using lists altogether and instead use a set from the start:&lt;/p&gt;
&lt;div class=&quot;highlight python pycon&quot;&gt;&lt;span class=&quot;repl-toggle&quot; title=&quot;Toggle REPL prompts and output&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;get_unique_words&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;... &lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;words&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;... &lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;range&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;... &lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;words&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get_random_word&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;... &lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;words&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get_unique_words&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;{&amp;#39;world&amp;#39;, &amp;#39;all&amp;#39;, &amp;#39;the&amp;#39;, &amp;#39;words&amp;#39;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This may not look much different than the other approaches except for making use of a set from the beginning. If you consider what&amp;rsquo;s happening within &lt;code&gt;.add()&lt;/code&gt;, it even sounds like the second approach: get the word, check if it&amp;rsquo;s already in the set, and if not, add it to the data structure.&lt;/p&gt;
&lt;p&gt;So why is using a set different from the second approach?&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s different because sets store elements in a manner that allows near-constant-time checks whether a value is in the set or not, unlike lists, which require linear-time lookups. The difference in lookup time means that the &lt;a href=&quot;https://stackoverflow.com/a/487278/2141768&quot;&gt;time complexity&lt;/a&gt; for adding to a set grows at a rate of O(N), which is much better than the O(N²) from the second approach in most cases.&lt;/p&gt;
&lt;h3 id=&quot;save-memory-with-generators&quot;&gt;Save Memory With Generators&lt;/h3&gt;
&lt;p&gt;List comprehensions are convenient tools but can sometimes lead to unnecessary memory usage.&lt;/p&gt;
&lt;p&gt;Imagine you&amp;rsquo;ve been asked to find the sum of the first 1000 perfect squares, starting with 1. You know about list comprehensions, so you quickly code up a working solution:&lt;/p&gt;
&lt;div class=&quot;highlight python pycon&quot;&gt;&lt;span class=&quot;repl-toggle&quot; title=&quot;Toggle REPL prompts and output&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sum&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;range&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1001&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)])&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;333833500&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Your solution makes a list of every perfect square between 1 and 1,000,000 and sums the values. Your code returns the right answer, but then your interviewer starts increasing the number of perfect squares you need to sum.&lt;/p&gt;
&lt;p&gt;At first, your function keeps popping out the right answer, but soon it starts slowing down until eventually the process seems to hang for an eternity. This is the last thing you want happening in a coding interview.&lt;/p&gt;
&lt;p&gt;What&amp;rsquo;s going on here?&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s making a list of every perfect square you&amp;rsquo;ve requested and summing them all. A list with 1000 perfect squares may not be large in computer-terms, but 100 million or 1 billion is quite a bit of information and can easily overwhelm your computer&amp;rsquo;s available memory resources. That&amp;rsquo;s what&amp;rsquo;s happening here.&lt;/p&gt;
&lt;p&gt;Thankfully, there&amp;rsquo;s a quick way to solve the memory problem. You just replace the brackets with parentheses:&lt;/p&gt;
&lt;div class=&quot;highlight python pycon&quot;&gt;&lt;span class=&quot;repl-toggle&quot; title=&quot;Toggle REPL prompts and output&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sum&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;range&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1001&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)))&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;333833500&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Swapping out the brackets changes your list comprehension into a &lt;a href=&quot;https://realpython.com/introduction-to-python-generators/&quot;&gt;generator expression&lt;/a&gt;. Generator expressions are perfect for when you know you want to retrieve data from a sequence, but you don&amp;rsquo;t need to access all of it at the same time.&lt;/p&gt;
&lt;p&gt;Instead of creating a list, the generator expression returns a &lt;code&gt;generator&lt;/code&gt; object. That object knows where it is in the current state (for example, &lt;code&gt;i = 49&lt;/code&gt;) and only calculates the next value when it&amp;rsquo;s asked for.&lt;/p&gt;
&lt;p&gt;So when &lt;code&gt;sum&lt;/code&gt; iterates over the generator object by calling &lt;code&gt;.__next__()&lt;/code&gt; repeatedly, the generator checks what &lt;code&gt;i&lt;/code&gt; equals, calculates &lt;code&gt;i * i&lt;/code&gt;, increments &lt;code&gt;i&lt;/code&gt; internally, and returns the proper value to &lt;code&gt;sum&lt;/code&gt;. The design allows generators to be used on massive sequences of data, because only one element exists in memory at a time.&lt;/p&gt;
&lt;h3 id=&quot;define-default-values-in-dictionaries-with-get-and-setdefault&quot;&gt;Define Default Values in Dictionaries With &lt;code&gt;.get()&lt;/code&gt; and &lt;code&gt;.setdefault()&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;One of the most common programming tasks involves adding, modifying, or retrieving an item that may or may not be in a dictionary. Python dictionaries have elegant functionality to make these tasks clean and easy, but developers often check explicitly for values when it isn&amp;rsquo;t necessary.&lt;/p&gt;
&lt;p&gt;Imagine you have a dictionary named &lt;code&gt;cowboy&lt;/code&gt;, and you want to get that cowboy&amp;rsquo;s name. One approach is to explicitly check for the key with a conditional:&lt;/p&gt;
&lt;div class=&quot;highlight python pycon&quot;&gt;&lt;span class=&quot;repl-toggle&quot; title=&quot;Toggle REPL prompts and output&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cowboy&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;age&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;horse&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;mustang&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;hat_size&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;large&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;name&amp;#39;&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cowboy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;... &lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cowboy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;name&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;... &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;... &lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;The Man with No Name&amp;#39;&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;...&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;&amp;#39;The Man with No Name&amp;#39;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This approach first checks if the &lt;code&gt;name&lt;/code&gt; key exists in the dictionary, and if so, it returns the corresponding value. Otherwise, it returns a default value.&lt;/p&gt;
&lt;p&gt;While explicitly checking for keys does work, it can easily be replaced with one line if you use &lt;code&gt;.get()&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight python pycon&quot;&gt;&lt;span class=&quot;repl-toggle&quot; title=&quot;Toggle REPL prompts and output&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cowboy&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;name&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;The Man with No Name&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;code&gt;get()&lt;/code&gt; performs the same operations that were performed in the first approach, but now they&amp;rsquo;re handled automatically. If the key exists, then the proper value will be returned. Otherwise, the default value will get returned.&lt;/p&gt;
&lt;p&gt;But what if you want to update the dictionary with a default value while still accessing the &lt;code&gt;name&lt;/code&gt; key? &lt;code&gt;.get()&lt;/code&gt; doesn&amp;rsquo;t really help you here, so you&amp;rsquo;re left with explicitly checking for the value again:&lt;/p&gt;
&lt;div class=&quot;highlight python pycon&quot;&gt;&lt;span class=&quot;repl-toggle&quot; title=&quot;Toggle REPL prompts and output&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;name&amp;#39;&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cowboy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;... &lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;cowboy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;name&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;The Man with No Name&amp;#39;&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;...&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cowboy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;name&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Checking for the value and setting a default is a valid approach and is easy to read, but again Python offers a more elegant method with &lt;code&gt;.setdefault()&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight python pycon&quot;&gt;&lt;span class=&quot;repl-toggle&quot; title=&quot;Toggle REPL prompts and output&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cowboy&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;setdefault&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;name&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;The Man with No Name&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;code&gt;.setdefault()&lt;/code&gt; accomplishes exactly the same thing as the snippet above. It checks if &lt;code&gt;name&lt;/code&gt; exists in &lt;code&gt;cowboy&lt;/code&gt;, and if so it returns that value. Otherwise, it sets &lt;code&gt;cowboy[&#39;name&#39;]&lt;/code&gt; to &lt;code&gt;The Man with No Name&lt;/code&gt; and returns the new value.&lt;/p&gt;
&lt;h2 id=&quot;take-advantage-of-pythons-standard-library&quot;&gt;Take Advantage of Python&amp;rsquo;s Standard Library&lt;/h2&gt;
&lt;p&gt;By default, Python comes with a lot of functionality that&amp;rsquo;s just an &lt;code&gt;import&lt;/code&gt; statement away. It&amp;rsquo;s powerful on its own, but knowing how to leverage the standard library can supercharge your coding interview skills.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s hard to pick the most useful pieces from all of the available modules, so this section will focus on just a small subset of its utility functions. Hopefully, these will prove useful to you in coding interviews and also whet your appetite to learn more about the advanced functionality of these and other modules.&lt;/p&gt;
&lt;h3 id=&quot;handle-missing-dictionary-keys-with-collectionsdefaultdict&quot;&gt;Handle Missing Dictionary Keys With &lt;code&gt;collections.defaultdict()&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;.get()&lt;/code&gt; and &lt;code&gt;.setdefault()&lt;/code&gt; work well when you&amp;rsquo;re setting a default for a single key, but it&amp;rsquo;s common to want a default value for all possible unset keys, especially when programming in a coding interview context.&lt;/p&gt;
&lt;p&gt;Pretend you have a group of students, and you need to keep track of their grades on homework assignments. The input value is a list of tuples with the format &lt;code&gt;(student_name, grade)&lt;/code&gt;, but you want to easily look up all the grades for a single student without iterating over the list.&lt;/p&gt;
&lt;p&gt;One way to store the grade data uses a dictionary that maps student names to lists of grades:&lt;/p&gt;
&lt;div class=&quot;highlight python pycon&quot;&gt;&lt;span class=&quot;repl-toggle&quot; title=&quot;Toggle REPL prompts and output&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;student_grades&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{}&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;grades&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;... &lt;/span&gt;    &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;elliot&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;91&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;... &lt;/span&gt;    &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;neelam&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;98&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;... &lt;/span&gt;    &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;bianca&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;81&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;... &lt;/span&gt;    &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;elliot&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;88&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;... &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;grade&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;grades&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;... &lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;student_grades&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;... &lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;student_grades&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;... &lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;student_grades&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;grade&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;...&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;student_grades&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;{&amp;#39;elliot&amp;#39;: [91, 88], &amp;#39;neelam&amp;#39;: [98], &amp;#39;bianca&amp;#39;: [81]}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In this approach, you iterate over the students and check if their names are already properties in the dictionary. If not, you add them to the dictionary with an empty list as the default value. You then append their actual grades to that student&amp;rsquo;s list of grades.&lt;/p&gt;
&lt;p&gt;But there&amp;rsquo;s an even cleaner approach that uses a &lt;code&gt;defaultdict&lt;/code&gt;,  which extends standard &lt;code&gt;dict&lt;/code&gt; functionality to allow you to set a default value that will be operated upon if the key doesn&amp;rsquo;t exist:&lt;/p&gt;
&lt;div class=&quot;highlight python pycon&quot;&gt;&lt;span class=&quot;repl-toggle&quot; title=&quot;Toggle REPL prompts and output&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;collections&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;defaultdict&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;student_grades&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;defaultdict&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;list&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;grade&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;grades&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;... &lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;student_grades&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;grade&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In this case, you&amp;rsquo;re creating a &lt;code&gt;defaultdict&lt;/code&gt; that uses the &lt;code&gt;list()&lt;/code&gt; constructor with no arguments as a default factory method. &lt;code&gt;list()&lt;/code&gt; with no arguments returns an empty list, so &lt;code&gt;defaultdict&lt;/code&gt; calls &lt;code&gt;list()&lt;/code&gt; if the name doesn&amp;rsquo;t exist and then allows the grade to be appended. If you want to get fancy, you could also use a lambda function as your factory value to return an arbitrary constant.&lt;/p&gt;
&lt;p&gt;Leveraging a &lt;code&gt;defaultdict&lt;/code&gt; can lead to cleaner application code because you don&amp;rsquo;t have to worry about default values at the key level. Instead, you can handle them once at the &lt;code&gt;defaultdict&lt;/code&gt; level and afterwards act as if the key is always present.&lt;/p&gt;
&lt;h3 id=&quot;count-hashable-objects-with-collectionscounter&quot;&gt;Count Hashable Objects With &lt;code&gt;collections.Counter&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;You have a long string of words with no punctuation or capital letters and you want to count how many times each word appears.&lt;/p&gt;
&lt;p&gt;You could use a dictionary or &lt;code&gt;defaultdict&lt;/code&gt; and increment the counts, but &lt;code&gt;collections.Counter&lt;/code&gt; provides a cleaner and more convenient way to do exactly that. Counter is a subclass of &lt;code&gt;dict&lt;/code&gt; that uses &lt;code&gt;0&lt;/code&gt; as the default value for any missing element and makes it easier to count occurrences of objects:&lt;/p&gt;
&lt;div class=&quot;highlight python pycon&quot;&gt;&lt;span class=&quot;repl-toggle&quot; title=&quot;Toggle REPL prompts and output&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;collections&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Counter&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;words&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;if there was there was but if &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;... &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;there was not there was not&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;counts&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Counter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;words&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;counts&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Counter({&amp;#39;if&amp;#39;: 2, &amp;#39;there&amp;#39;: 4, &amp;#39;was&amp;#39;: 4, &amp;#39;not&amp;#39;: 2, &amp;#39;but&amp;#39;: 1})&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;When you pass in the list of words to &lt;code&gt;Counter&lt;/code&gt;, it stores each word along with a count of how many times that word occurred in the list.&lt;/p&gt;
&lt;p&gt;Are you curious what the two most common words were? Just use &lt;code&gt;.most_common()&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight python pycon&quot;&gt;&lt;span class=&quot;repl-toggle&quot; title=&quot;Toggle REPL prompts and output&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;counts&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;most_common&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;[(&amp;#39;there&amp;#39;, 4), (&amp;#39;was&amp;#39;, 4)]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;code&gt;.most_common()&lt;/code&gt; is a convenience method and simply returns the &lt;code&gt;n&lt;/code&gt; most frequent inputs by count.&lt;/p&gt;
&lt;h3 id=&quot;access-common-string-groups-with-string-constants&quot;&gt;Access Common String Groups With &lt;code&gt;string&lt;/code&gt; Constants&lt;/h3&gt;
&lt;p&gt;It&amp;rsquo;s trivia time! Is &lt;code&gt;&#39;A&#39; &amp;gt; &#39;a&#39;&lt;/code&gt; true or false?&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s false, because the ASCII code for &lt;code&gt;A&lt;/code&gt; is 65, but &lt;code&gt;a&lt;/code&gt; is 97, and 65 is not greater than 97.&lt;/p&gt;
&lt;p&gt;Why does the answer matter? Because if you want to check if a character is part of the English alphabet, one popular way is to see if it&amp;rsquo;s between &lt;code&gt;A&lt;/code&gt; and &lt;code&gt;z&lt;/code&gt; (65 and 122 on the ASCII chart).&lt;/p&gt;
&lt;p&gt;Checking the ASCII code works but is clumsy and easy to mess up in coding interviews, especially if you can&amp;rsquo;t remember whether lowercase or uppercase ASCII characters come first. It&amp;rsquo;s much easier to use the constants defined as part of the &lt;a href=&quot;https://docs.python.org/3/library/string.html&quot;&gt;&lt;code&gt;string&lt;/code&gt; module&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;You can see one in use in &lt;code&gt;is_upper()&lt;/code&gt;, which returns whether all characters in a string are uppercase letters:&lt;/p&gt;
&lt;div class=&quot;highlight python pycon&quot;&gt;&lt;span class=&quot;repl-toggle&quot; title=&quot;Toggle REPL prompts and output&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;string&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;is_upper&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;word&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;... &lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;letter&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;word&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;... &lt;/span&gt;        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;letter&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ascii_uppercase&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;... &lt;/span&gt;            &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;False&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;... &lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;True&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;...&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;is_upper&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;Thanks Geir&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;False&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;is_upper&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;LOL&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;True&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;code&gt;is_upper()&lt;/code&gt; iterates over the letters in &lt;code&gt;word&lt;/code&gt;, and checks if the letters are part of &lt;code&gt;string.ascii_uppercase&lt;/code&gt;. If you print out &lt;code&gt;string.ascii_uppercase&lt;/code&gt; you&amp;rsquo;ll see that it&amp;rsquo;s just a lowly string. The value is set to the literal &lt;code&gt;&#39;ABCDEFGHIJKLMNOPQRSTUVWXYZ&#39;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;All &lt;code&gt;string&lt;/code&gt; constants are just strings of frequently referenced string values. They include the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;string.ascii_letters&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;string.ascii_uppercase&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;string.ascii_lowercase&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;string.digits&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;string.hexdigits&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;string.octdigits&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;string.punctuation&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;string.printable&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;string.whitespace&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These are easier to use and, even more importantly, easier to read.&lt;/p&gt;
&lt;h3 id=&quot;generate-permutations-and-combinations-with-itertools&quot;&gt;Generate Permutations and Combinations With &lt;code&gt;itertools&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;Interviewers love to give real life scenarios to make coding interviews seem less intimidating, so here&amp;rsquo;s a contrived example: you go to an amusement park and decide to figure out every possible pair of friends that could sit together on a roller coaster.&lt;/p&gt;
&lt;p&gt;Unless generating these pairs is the primary purpose of the interview question, it&amp;rsquo;s likely that generating all the possible pairs is just a tedious step on the way towards a working algorithm. You could calculate them yourself with nested for-loops, or you could use the powerful &lt;a href=&quot;https://realpython.com/python-itertools/&quot;&gt;&lt;code&gt;itertools&lt;/code&gt; library&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;itertools&lt;/code&gt; has multiple tools for generating iterable sequences of input data, but right now we&amp;rsquo;ll just focus on two common functions: &lt;code&gt;itertools.permutations()&lt;/code&gt; and &lt;code&gt;itertools.combinations()&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;itertools.permutations()&lt;/code&gt; builds a list of all permutations, meaning it&amp;rsquo;s a list of every possible grouping of input values with a length matching the &lt;code&gt;count&lt;/code&gt; parameter. The &lt;code&gt;r&lt;/code&gt; keyword argument lets us specify how many values go in each grouping:&lt;/p&gt;
&lt;div class=&quot;highlight python pycon&quot;&gt;&lt;span class=&quot;repl-toggle&quot; title=&quot;Toggle REPL prompts and output&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;itertools&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;friends&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;Monique&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;Ashish&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;Devon&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;Bernie&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;list&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;itertools&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;permutations&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;friends&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;[(&amp;#39;Monique&amp;#39;, &amp;#39;Ashish&amp;#39;), (&amp;#39;Monique&amp;#39;, &amp;#39;Devon&amp;#39;), (&amp;#39;Monique&amp;#39;, &amp;#39;Bernie&amp;#39;),&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;(&amp;#39;Ashish&amp;#39;, &amp;#39;Monique&amp;#39;), (&amp;#39;Ashish&amp;#39;, &amp;#39;Devon&amp;#39;), (&amp;#39;Ashish&amp;#39;, &amp;#39;Bernie&amp;#39;),&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;(&amp;#39;Devon&amp;#39;, &amp;#39;Monique&amp;#39;), (&amp;#39;Devon&amp;#39;, &amp;#39;Ashish&amp;#39;), (&amp;#39;Devon&amp;#39;, &amp;#39;Bernie&amp;#39;),&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;(&amp;#39;Bernie&amp;#39;, &amp;#39;Monique&amp;#39;), (&amp;#39;Bernie&amp;#39;, &amp;#39;Ashish&amp;#39;), (&amp;#39;Bernie&amp;#39;, &amp;#39;Devon&amp;#39;)]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;With permutations, the order of the elements matters, so &lt;code&gt;(&#39;sam&#39;, &#39;devon&#39;)&lt;/code&gt; represents a different pairing than &lt;code&gt;(&#39;devon&#39;, &#39;sam&#39;)&lt;/code&gt;, meaning that they would both be included in the list.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;itertools.combinations()&lt;/code&gt; builds combinations. These are also the possible groupings of the input values, but now the order of the values doesn&amp;rsquo;t matter. Because &lt;code&gt;(&#39;sam&#39;, &#39;devon&#39;)&lt;/code&gt; and &lt;code&gt;(&#39;devon&#39;, &#39;sam&#39;)&lt;/code&gt; represent the same pair, only one of them would be included in the output list:&lt;/p&gt;
&lt;div class=&quot;highlight python pycon&quot;&gt;&lt;span class=&quot;repl-toggle&quot; title=&quot;Toggle REPL prompts and output&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;list&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;itertools&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;combinations&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;friends&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;[(&amp;#39;Monique&amp;#39;, &amp;#39;Ashish&amp;#39;), (&amp;#39;Monique&amp;#39;, &amp;#39;Devon&amp;#39;), (&amp;#39;Monique&amp;#39;, &amp;#39;Bernie&amp;#39;),&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;(&amp;#39;Ashish&amp;#39;, &amp;#39;Devon&amp;#39;), (&amp;#39;Ashish&amp;#39;, &amp;#39;Bernie&amp;#39;), (&amp;#39;Devon&amp;#39;, &amp;#39;Bernie&amp;#39;)]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Since the order of the values matters with combinations, there are fewer combinations than permutations for the same input list. Again, because we set &lt;code&gt;r&lt;/code&gt; to 2, each grouping has two names in it.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;.combinations()&lt;/code&gt; and &lt;code&gt;.permutations()&lt;/code&gt; are just small examples of a powerful library, but even these two functions can be quite useful when you&amp;rsquo;re trying to solve an algorithm problem quickly.&lt;/p&gt;
&lt;h2 id=&quot;conclusion-coding-interview-superpowers&quot;&gt;Conclusion: Coding Interview Superpowers&lt;/h2&gt;
&lt;p&gt;You can now feel comfortable using some of Python&amp;rsquo;s less common, but more powerful, standard features in your next coding interview. There&amp;rsquo;s a lot to learn about the language as a whole but this article should have given you a starting point to go deeper while letting you use Python more effectively when you interview.&lt;/p&gt;
&lt;p&gt;In this article, you&amp;rsquo;ve learned different types of standard tools to supercharge your coding interview skills:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.python.org/3/library/functions.html#built-in-functions&quot;&gt;Powerful built-in functions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Data structures built to handle common scenarios with barely any code&lt;/li&gt;
&lt;li&gt;Standard library packages that have feature-rich solutions for specific problems, letting you write better code faster&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Interviewing may not be the best approximation of real software development, but it&amp;rsquo;s worth knowing how to succeed in any programming environment, even interviews. Thankfully, learning how to use Python during coding interviews can help you understand the language more deeply, which will pay dividends during day-to-day development.&lt;/p&gt;
        &lt;hr /&gt;
        &lt;p&gt;&lt;em&gt;[ Improve Your Python With 🐍 Python Tricks 💌 – Get a short &amp;amp; sweet Python Trick delivered to your inbox every couple of days. &lt;a href=&quot;https://realpython.com/python-tricks/?utm_source=realpython&amp;amp;utm_medium=rss&amp;amp;utm_campaign=footer&quot;&gt;&amp;gt;&amp;gt; Click here to learn more and see examples&lt;/a&gt; ]&lt;/em&gt;&lt;/p&gt;
      </content>
    </entry>
  
    <entry>
      <title>Django Migrations 101</title>
      <id>https://realpython.com/courses/django-migrations-101/</id>
      <link href="https://realpython.com/courses/django-migrations-101/"/>
      <updated>2019-03-26T14:00:00+00:00</updated>
      <summary>With this course you’ll get comfortable with Django migrations and learn how to create database tables without writing any SQL, how to automatically modify your database after you changed your models, and how to revert changes made to your database.</summary>
      <content type="html">
        &lt;p&gt;Since version 1.7, Django has come with built-in support for database migrations. In Django, database migrations usually go hand in hand with models: whenever you code up a new model, you also generate a migration to create the necessary table in the database. However, migrations can do much more.&lt;/p&gt;
&lt;p&gt;With this course you’ll get comfortable with Django migrations and learn how to create database tables without writing any SQL, how to automatically modify your database after you changed your models, and how to revert changes made to your database.&lt;/p&gt;
        &lt;hr /&gt;
        &lt;p&gt;&lt;em&gt;[ Improve Your Python With 🐍 Python Tricks 💌 – Get a short &amp;amp; sweet Python Trick delivered to your inbox every couple of days. &lt;a href=&quot;https://realpython.com/python-tricks/?utm_source=realpython&amp;amp;utm_medium=rss&amp;amp;utm_campaign=footer&quot;&gt;&amp;gt;&amp;gt; Click here to learn more and see examples&lt;/a&gt; ]&lt;/em&gt;&lt;/p&gt;
      </content>
    </entry>
  
    <entry>
      <title>Documenting Python Projects With Sphinx and Read The Docs</title>
      <id>https://realpython.com/courses/documenting-python-projects-sphinx-read-the-docs/</id>
      <link href="https://realpython.com/courses/documenting-python-projects-sphinx-read-the-docs/"/>
      <updated>2019-03-26T13:30:00+00:00</updated>
      <summary>In this video series we&#39;ll cover creating Python documentation from scratch using Sphinx, as well as getting your code repository hooked up to Read The Docs, to automatically build and publish your code documentation.</summary>
      <content type="html">
        &lt;p&gt;In this video series we&amp;rsquo;ll cover creating Python documentation from scratch using Sphinx, as well as getting your code repository hooked up to Read The Docs, to automatically build and publish your code documentation.&lt;/p&gt;
&lt;div class=&quot;alert alert-primary&quot; role=&quot;alert&quot;&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; This course uses Python 2.7 in its coding examples.&lt;/p&gt;
&lt;/div&gt;
&lt;h3 id=&quot;resources&quot;&gt;Resources&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/myusuf3/doctut&quot;&gt;&lt;code&gt;doctut&lt;/code&gt; Example Project&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://doctut.readthedocs.io/en/latest/&quot;&gt;&lt;code&gt;doctut&lt;/code&gt; Example Docs on Read The Docs&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
        &lt;hr /&gt;
        &lt;p&gt;&lt;em&gt;[ Improve Your Python With 🐍 Python Tricks 💌 – Get a short &amp;amp; sweet Python Trick delivered to your inbox every couple of days. &lt;a href=&quot;https://realpython.com/python-tricks/?utm_source=realpython&amp;amp;utm_medium=rss&amp;amp;utm_campaign=footer&quot;&gt;&amp;gt;&amp;gt; Click here to learn more and see examples&lt;/a&gt; ]&lt;/em&gt;&lt;/p&gt;
      </content>
    </entry>
  
    <entry>
      <title>An Intro to Threading in Python</title>
      <id>https://realpython.com/intro-to-python-threading/</id>
      <link href="https://realpython.com/intro-to-python-threading/"/>
      <updated>2019-03-25T14:00:00+00:00</updated>
      <summary>In this intermediate-level tutorial, you&#39;ll learn how to use threading in your Python programs. You&#39;ll see how to create threads, how to coordinate and synchronize them, and how to handle common problems that arise in threading.</summary>
      <content type="html">
        &lt;p&gt;Python threading allows you to have different parts of your program run concurrently and can simplify your design. If you&amp;rsquo;ve got some experience in Python and want to speed up your program using threads, then this tutorial is for you!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;In this article, you&amp;rsquo;ll learn:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;What threads are&lt;/li&gt;
&lt;li&gt;How to create threads and wait for them to finish&lt;/li&gt;
&lt;li&gt;How to use a &lt;code&gt;ThreadPoolExecutor&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;How to avoid race conditions&lt;/li&gt;
&lt;li&gt;How to use the common tools that Python &lt;code&gt;threading&lt;/code&gt; provides&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This article assumes you&amp;rsquo;ve got the Python basics down pat and that you&amp;rsquo;re using at least version 3.6 to run the examples. If you need a refresher, you can start with the &lt;a href=&quot;https://realpython.com/learning-paths/&quot;&gt;Python Learning Paths&lt;/a&gt; and get up to speed.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re not sure if you want to use Python &lt;code&gt;threading&lt;/code&gt;, &lt;code&gt;asyncio&lt;/code&gt;, or &lt;code&gt;multiprocessing&lt;/code&gt;, then you can check out &lt;a href=&quot;https://realpython.com/python-concurrency/&quot;&gt;Speed Up Your Python Program With Concurrency&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;All of the sources used in this tutorial are available to you in the &lt;a href=&quot;https://github.com/realpython/materials/tree/master/intro-to-threading&quot;&gt;&lt;em&gt;Real Python&lt;/em&gt; GitHub repo&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;alert alert-warning&quot; role=&quot;alert&quot;&gt;&lt;p&gt;&lt;strong&gt;Free Bonus:&lt;/strong&gt; &lt;a href=&quot;&quot; class=&quot;alert-link&quot; data-toggle=&quot;modal&quot; data-target=&quot;#modal-python-mastery-course&quot; data-focus=&quot;false&quot;&gt;5 Thoughts On Python Mastery&lt;/a&gt;, a free course for Python developers that shows you the roadmap and the mindset you&#39;ll need to take your Python skills to the next level.&lt;/p&gt;&lt;/div&gt;

&lt;div class=&quot;alert alert-primary&quot; role=&quot;alert&quot;&gt;
&lt;p&gt;&lt;strong&gt;&lt;i class=&quot;fa fa-graduation-cap&quot; aria-hidden=&quot;true&quot;&gt;&lt;/i&gt; Take the Quiz:&lt;/strong&gt; Test your knowledge with our interactive “Python Threading” quiz. Upon completion you will receive a score so you can track your learning progress over time:&lt;/p&gt;&lt;p class=&quot;text-center my-2&quot;&gt;&lt;a class=&quot;btn btn-primary&quot; href=&quot;/quizzes/python-threading/&quot; target=&quot;_blank&quot;&gt;Take the Quiz »&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;

&lt;h2 id=&quot;what-is-a-thread&quot;&gt;What Is a Thread?&lt;/h2&gt;
&lt;p&gt;A thread is a separate flow of execution. This means that your program will have two things happening at once. But for most Python 3 implementations the different threads do not actually execute at the same time: they merely appear to.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s tempting to think of threading as having two (or more) different processors running on your program, each one doing an independent task at the same time. That&amp;rsquo;s almost right. The threads may be running on different processors, but they will only be running one at a time. &lt;/p&gt;
&lt;p&gt;Getting multiple tasks running simultaneously requires a non-standard implementation of Python, writing some of your code in a different language, or using &lt;code&gt;multiprocessing&lt;/code&gt; which comes with some extra overhead.&lt;/p&gt;
&lt;p&gt;Because of the way CPython implementation of Python works, threading may not speed up all tasks.  This is due to interactions with the &lt;a href=&quot;https://realpython.com/python-gil/&quot;&gt;GIL&lt;/a&gt; that essentially limit one Python thread to run at a time. &lt;/p&gt;
&lt;p&gt;Tasks that spend much of their time waiting for external events are generally good candidates for threading.  Problems that require heavy CPU computation and spend little time waiting for external events might not run faster at all.  &lt;/p&gt;
&lt;p&gt;This is true for code written in Python and running on the standard CPython implementation.  If your threads are written in C they have the ability to release the GIL and run concurrently.  If you are running on a different Python implementation, check with the documentation too see how it handles threads.  &lt;/p&gt;
&lt;p&gt;If you are running a standard Python implementation, writing in only Python, and have a CPU-bound problem, you should check out the &lt;code&gt;multiprocessing&lt;/code&gt; module instead.&lt;/p&gt;
&lt;p&gt;Architecting your program to use threading can also provide gains in design clarity. Most of the examples you&amp;rsquo;ll learn about in this tutorial are not necessarily going to run faster because they use threads. Using threading in them helps to make the design cleaner and easier to reason about.&lt;/p&gt;
&lt;p&gt;So, let&amp;rsquo;s stop talking about threading and start using it!&lt;/p&gt;
&lt;h2 id=&quot;starting-a-thread&quot;&gt;Starting a Thread&lt;/h2&gt;
&lt;p&gt;Now that you&amp;rsquo;ve got an idea of what a thread is, let&amp;rsquo;s learn how to make one. The Python standard library provides &lt;a href=&quot;https://docs.python.org/3/library/threading.html&quot;&gt;&lt;code&gt;threading&lt;/code&gt;&lt;/a&gt;, which contains most of the primitives you&amp;rsquo;ll see in this article. &lt;code&gt;Thread&lt;/code&gt;, in this module, nicely encapsulates threads, providing a clean interface to work with them.&lt;/p&gt;
&lt;p&gt;To start a separate thread, you create a &lt;code&gt;Thread&lt;/code&gt; instance and then tell it to &lt;code&gt;.start()&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight python&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;lineno&quot;&gt; 1 &lt;/span&gt;&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;logging&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 2 &lt;/span&gt;&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;threading&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 3 &lt;/span&gt;&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;time&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 4 &lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 5 &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;thread_function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 6 &lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;logging&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;info&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;Thread &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%s&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;: starting&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 7 &lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sleep&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 8 &lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;logging&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;info&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;Thread &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%s&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;: finishing&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 9 &lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;10 &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;vm&quot;&gt;__name__&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;__main__&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;11 &lt;/span&gt;    &lt;span class=&quot;nb&quot;&gt;format&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%(asctime)s&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%(message)s&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;12 &lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;logging&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;basicConfig&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;format&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;format&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;level&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;logging&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;INFO&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;13 &lt;/span&gt;                        &lt;span class=&quot;n&quot;&gt;datefmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;%H:%M:%S&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;14 &lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;15 &lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;logging&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;info&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;Main    : before creating thread&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;16 &lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;threading&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Thread&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;target&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;thread_function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,))&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;17 &lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;logging&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;info&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;Main    : before running thread&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;18 &lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;start&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;19 &lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;logging&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;info&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;Main    : wait for the thread to finish&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;20 &lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;# x.join()&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;21 &lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;logging&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;info&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;Main    : all done&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;If you look around the logging statements, you can see that the &lt;code&gt;main&lt;/code&gt; section is creating and starting the thread:&lt;/p&gt;
&lt;div class=&quot;highlight python&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;threading&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Thread&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;target&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;thread_function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,))&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;start&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;When you create a &lt;code&gt;Thread&lt;/code&gt;, you pass it a function and a list containing the arguments to that function. In this case, you&amp;rsquo;re telling the &lt;code&gt;Thread&lt;/code&gt; to run &lt;code&gt;thread_function()&lt;/code&gt; and to pass it &lt;code&gt;1&lt;/code&gt; as an argument.&lt;/p&gt;
&lt;p&gt;For this article, you&amp;rsquo;ll use sequential integers as names for your threads. There is &lt;code&gt;threading.get_ident()&lt;/code&gt;, which returns a unique name for each thread, but these are usually neither short nor easily readable.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;thread_function()&lt;/code&gt; itself doesn&amp;rsquo;t do much. It simply logs some messages with a &lt;code&gt;time.sleep()&lt;/code&gt; in between them.&lt;/p&gt;
&lt;p&gt;When you run this program as it is (with line twenty commented out), the output will look like this:&lt;/p&gt;
&lt;div class=&quot;highlight sh&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; ./single_thread.py
&lt;span class=&quot;go&quot;&gt;Main    : before creating thread&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Main    : before running thread&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Thread 1: starting&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Main    : wait for the thread to finish&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Main    : all done&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Thread 1: finishing&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You&amp;rsquo;ll notice that the &lt;code&gt;Thread&lt;/code&gt; finished after the &lt;code&gt;Main&lt;/code&gt; section of your code did. You&amp;rsquo;ll come back to why that is and talk about the mysterious line twenty in the next section.&lt;/p&gt;
&lt;h3 id=&quot;daemon-threads&quot;&gt;Daemon Threads&lt;/h3&gt;
&lt;p&gt;In computer science, a &lt;a href=&quot;https://en.wikipedia.org/wiki/Daemon_(computing)&quot;&gt;&lt;code&gt;daemon&lt;/code&gt;&lt;/a&gt; is a process that runs in the background.&lt;/p&gt;
&lt;p&gt;Python &lt;code&gt;threading&lt;/code&gt; has a more specific meaning for &lt;code&gt;daemon&lt;/code&gt;. A &lt;code&gt;daemon&lt;/code&gt; thread will shut down immediately when the program exits. One way to think about these definitions is to consider the &lt;code&gt;daemon&lt;/code&gt; thread a thread that runs in the background without worrying about shutting it down.&lt;/p&gt;
&lt;p&gt;If a program is running &lt;code&gt;Threads&lt;/code&gt; that are not &lt;code&gt;daemons&lt;/code&gt;, then the program will wait for those threads to complete before it terminates. &lt;code&gt;Threads&lt;/code&gt; that &lt;em&gt;are&lt;/em&gt; daemons, however, are just killed wherever they are when the program is exiting.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s look a little more closely at the output of your program above. The last two lines are the interesting bit. When you run the program, you&amp;rsquo;ll notice that there is a pause (of about 2 seconds) after &lt;code&gt;__main__&lt;/code&gt; has printed its &lt;code&gt;all done&lt;/code&gt; message and before the thread is finished.&lt;/p&gt;
&lt;p&gt;This pause is Python waiting for the non-daemonic thread to complete. When your Python program ends, part of the shutdown process is to clean up the threading routine.&lt;/p&gt;
&lt;p&gt;If you look at the &lt;a href=&quot;https://github.com/python/cpython/blob/df5cdc11123a35065bbf1636251447d0bfe789a5/Lib/threading.py#L1263&quot;&gt;source for Python &lt;code&gt;threading&lt;/code&gt;&lt;/a&gt;, you&amp;rsquo;ll see that &lt;code&gt;threading._shutdown()&lt;/code&gt; walks through all of the running threads and calls &lt;code&gt;.join()&lt;/code&gt; on every one that does not have the &lt;code&gt;daemon&lt;/code&gt; flag set.&lt;/p&gt;
&lt;p&gt;So your program waits to exit because the thread itself is waiting in a sleep. As soon as it has completed and printed the message, &lt;code&gt;.join()&lt;/code&gt; will return and the program can exit.&lt;/p&gt;
&lt;p&gt;Frequently, this behavior is what you want, but there are other options available to us. Let&amp;rsquo;s first repeat the program with a &lt;code&gt;daemon&lt;/code&gt; thread. You do that by changing how you construct the &lt;code&gt;Thread&lt;/code&gt;, adding the &lt;code&gt;daemon=True&lt;/code&gt; flag:&lt;/p&gt;
&lt;div class=&quot;highlight python&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;threading&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Thread&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;target&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;thread_function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;daemon&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;When you run the program now, you should see this output:&lt;/p&gt;
&lt;div class=&quot;highlight sh&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; ./daemon_thread.py
&lt;span class=&quot;go&quot;&gt;Main    : before creating thread&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Main    : before running thread&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Thread 1: starting&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Main    : wait for the thread to finish&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Main    : all done&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The difference here is that the final line of the output is missing. &lt;code&gt;thread_function()&lt;/code&gt; did not get a chance to complete. It was a &lt;code&gt;daemon&lt;/code&gt; thread, so when &lt;code&gt;__main__&lt;/code&gt; reached the end of its code and the program wanted to finish, the daemon was killed.&lt;/p&gt;
&lt;h3 id=&quot;join-a-thread&quot;&gt;&lt;code&gt;join()&lt;/code&gt; a Thread&lt;/h3&gt;
&lt;p&gt;Daemon threads are handy, but what about when you want to wait for a thread to stop? What about when you want to do that and not exit your program? Now let&amp;rsquo;s go back to your original program and look at that commented out line twenty:&lt;/p&gt;
&lt;div class=&quot;highlight python&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;# x.join()&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;To tell one thread to wait for another thread to finish, you call &lt;code&gt;.join()&lt;/code&gt;. If you uncomment that line, the main thread will pause and wait for the thread &lt;code&gt;x&lt;/code&gt; to complete running.&lt;/p&gt;
&lt;p&gt;Did you test this on the code with the daemon thread or the regular thread? It turns out that it doesn&amp;rsquo;t matter. If you &lt;code&gt;.join()&lt;/code&gt; a thread, that statement will wait until either kind of thread is finished.&lt;/p&gt;
&lt;h2 id=&quot;working-with-many-threads&quot;&gt;Working With Many Threads&lt;/h2&gt;
&lt;p&gt;The example code so far has only been working with two threads: the main thread and one you started with the &lt;code&gt;threading.Thread&lt;/code&gt; object. &lt;/p&gt;
&lt;p&gt;Frequently, you&amp;rsquo;ll want to start a number of threads and have them do interesting work. Let&amp;rsquo;s start by looking at the harder way of doing that, and then you&amp;rsquo;ll move on to an easier method.&lt;/p&gt;
&lt;p&gt;The harder way of starting multiple threads is the one you already know:&lt;/p&gt;
&lt;div class=&quot;highlight python&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;logging&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;threading&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;time&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;thread_function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;logging&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;info&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;Thread &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%s&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;: starting&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sleep&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;logging&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;info&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;Thread &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%s&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;: finishing&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;vm&quot;&gt;__name__&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;__main__&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;format&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%(asctime)s&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%(message)s&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;logging&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;basicConfig&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;format&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;format&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;level&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;logging&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;INFO&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                        &lt;span class=&quot;n&quot;&gt;datefmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;%H:%M:%S&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;threads&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;list&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;index&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;range&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;logging&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;info&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;Main    : create and start thread &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%d&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;.&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;threading&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Thread&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;target&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;thread_function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,))&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;threads&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;start&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;thread&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;enumerate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;threads&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;logging&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;info&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;Main    : before joining thread &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%d&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;.&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;thread&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;logging&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;info&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;Main    : thread &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%d&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; done&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This code uses the same mechanism you saw above to start a thread, create a &lt;code&gt;Thread&lt;/code&gt; object, and then call &lt;code&gt;.start()&lt;/code&gt;. The program keeps a list of &lt;code&gt;Thread&lt;/code&gt; objects so that it can then wait for them later using &lt;code&gt;.join()&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Running this code multiple times will likely produce some interesting results. Here&amp;rsquo;s an example output from my machine:&lt;/p&gt;
&lt;div class=&quot;highlight sh&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; ./multiple_threads.py
&lt;span class=&quot;go&quot;&gt;Main    : create and start thread 0.&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Thread 0: starting&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Main    : create and start thread 1.&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Thread 1: starting&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Main    : create and start thread 2.&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Thread 2: starting&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Main    : before joining thread 0.&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Thread 2: finishing&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Thread 1: finishing&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Thread 0: finishing&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Main    : thread 0 done&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Main    : before joining thread 1.&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Main    : thread 1 done&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Main    : before joining thread 2.&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Main    : thread 2 done&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;If you walk through the output carefully, you&amp;rsquo;ll see all three threads getting started in the order you might expect, but in this case they finish in the opposite order! Multiple runs will produce different orderings. Look for the &lt;code&gt;Thread x: finishing&lt;/code&gt; message to tell you when each thread is done.&lt;/p&gt;
&lt;p&gt;The order in which threads are run is determined by the operating system and can be quite hard to predict. It may (and likely will) vary from run to run, so you need to be aware of that when you design algorithms that use threading.&lt;/p&gt;
&lt;p&gt;Fortunately, Python gives you several primitives that you&amp;rsquo;ll look at later to help coordinate threads and get them running together. Before that, let&amp;rsquo;s look at how to make managing a group of threads a bit easier.&lt;/p&gt;
&lt;h2 id=&quot;using-a-threadpoolexecutor&quot;&gt;Using a &lt;code&gt;ThreadPoolExecutor&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;There&amp;rsquo;s an easier way to start up a group of threads than the one you saw above. It&amp;rsquo;s called a &lt;code&gt;ThreadPoolExecutor&lt;/code&gt;, and it&amp;rsquo;s part of the standard library in &lt;a href=&quot;https://docs.python.org/3/library/concurrent.futures.html&quot;&gt;&lt;code&gt;concurrent.futures&lt;/code&gt;&lt;/a&gt; (as of Python 3.2).&lt;/p&gt;
&lt;p&gt;The easiest way to create it is as a context manager, using the &lt;code&gt;with&lt;/code&gt; statement to manage the creation and destruction of the pool.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s the &lt;code&gt;__main__&lt;/code&gt; from the last example rewritten to use a &lt;code&gt;ThreadPoolExecutor&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight python&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;concurrent.futures&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# [rest of code]&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;vm&quot;&gt;__name__&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;__main__&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;format&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%(asctime)s&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%(message)s&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;logging&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;basicConfig&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;format&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;format&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;level&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;logging&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;INFO&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                        &lt;span class=&quot;n&quot;&gt;datefmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;%H:%M:%S&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;concurrent&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;futures&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ThreadPoolExecutor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;max_workers&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;executor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;executor&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;thread_function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;range&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The code creates a &lt;code&gt;ThreadPoolExecutor&lt;/code&gt; as a context manager, telling it how many worker threads it wants in the pool. It then uses &lt;code&gt;.map()&lt;/code&gt; to step through an iterable of things, in your case &lt;code&gt;range(3)&lt;/code&gt;, passing each one to a thread in the pool.&lt;/p&gt;
&lt;p&gt;The end of the &lt;code&gt;with&lt;/code&gt; block causes the &lt;code&gt;ThreadPoolExecutor&lt;/code&gt; to do a &lt;code&gt;.join()&lt;/code&gt; on each of the threads in the pool. It is &lt;em&gt;strongly&lt;/em&gt; recommended that you use &lt;code&gt;ThreadPoolExecutor&lt;/code&gt; as a context manager when you can so that you never forget to &lt;code&gt;.join()&lt;/code&gt; the threads.&lt;/p&gt;
&lt;div class=&quot;alert alert-primary&quot; role=&quot;alert&quot;&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Using a &lt;code&gt;ThreadPoolExecutor&lt;/code&gt; can cause some confusing errors. &lt;/p&gt;
&lt;p&gt;For example, if you call a function that takes no parameters, but you pass it parameters in &lt;code&gt;.map()&lt;/code&gt;, the thread will throw an exception.&lt;/p&gt;
&lt;p&gt;Unfortunately, &lt;code&gt;ThreadPoolExecutor&lt;/code&gt; will hide that exception, and (in the case above) the program terminates with no output. This can be quite confusing to debug at first.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;Running your corrected example code will produce output that looks like this:&lt;/p&gt;
&lt;div class=&quot;highlight sh&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; ./executor.py
&lt;span class=&quot;go&quot;&gt;Thread 0: starting&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Thread 1: starting&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Thread 2: starting&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Thread 1: finishing&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Thread 0: finishing&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Thread 2: finishing&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Again, notice how &lt;code&gt;Thread 1&lt;/code&gt; finished before &lt;code&gt;Thread 0&lt;/code&gt;. The scheduling of threads is done by the operating system and does not follow a plan that&amp;rsquo;s easy to figure out.&lt;/p&gt;
&lt;h2 id=&quot;race-conditions&quot;&gt;Race Conditions&lt;/h2&gt;
&lt;p&gt;Before you move on to some of the other features tucked away in Python &lt;code&gt;threading&lt;/code&gt;, let&amp;rsquo;s talk a bit about one of the more difficult issues you&amp;rsquo;ll run into when writing threaded programs: &lt;a href=&quot;https://en.wikipedia.org/wiki/Race_condition&quot;&gt;race conditions&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Once you&amp;rsquo;ve seen what a race condition is and looked at one happening, you&amp;rsquo;ll move on to some of the primitives provided by the standard library to prevent race conditions from happening.&lt;/p&gt;
&lt;p&gt;Race conditions can occur when two or more threads access a shared piece of data or resource. In this example, you&amp;rsquo;re going to create a large race condition that happens every time, but be aware that most race conditions are not this obvious. Frequently, they only occur rarely, and they can produce confusing results. As you can imagine, this makes them quite difficult to debug.&lt;/p&gt;
&lt;p&gt;Fortunately, this race condition will happen every time, and you&amp;rsquo;ll walk through it in detail to explain what is happening.&lt;/p&gt;
&lt;p&gt;For this example, you&amp;rsquo;re going to write a class that updates a database. Okay, you&amp;rsquo;re not really going to have a database: you&amp;rsquo;re just going to fake it, because that&amp;rsquo;s not the point of this article.&lt;/p&gt;
&lt;p&gt;Your &lt;code&gt;FakeDatabase&lt;/code&gt; will have &lt;code&gt;.__init__()&lt;/code&gt; and &lt;code&gt;.update()&lt;/code&gt; methods:&lt;/p&gt;
&lt;div class=&quot;highlight python&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;FakeDatabase&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;__init__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;update&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;logging&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;info&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;Thread &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%s&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;: starting update&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;local_copy&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;local_copy&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sleep&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;local_copy&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;logging&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;info&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;Thread &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%s&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;: finishing update&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;code&gt;FakeDatabase&lt;/code&gt; is keeping track of a single number: &lt;code&gt;.value&lt;/code&gt;. This is going to be the shared data on which you&amp;rsquo;ll see the race condition.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;.__init__()&lt;/code&gt; simply initializes &lt;code&gt;.value&lt;/code&gt; to zero. So far, so good.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;.update()&lt;/code&gt; looks a little strange. It&amp;rsquo;s simulating reading a value from a database, doing some computation on it, and then writing a new value back to the database.&lt;/p&gt;
&lt;p&gt;In this case, reading from the database just means copying &lt;code&gt;.value&lt;/code&gt; to a local variable. The computation is just to add one to the value and then &lt;code&gt;.sleep()&lt;/code&gt; for a little bit. Finally, it writes the value back by copying the local value back to &lt;code&gt;.value&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s how you&amp;rsquo;ll use this &lt;code&gt;FakeDatabase&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight python&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;vm&quot;&gt;__name__&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;__main__&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;format&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%(asctime)s&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%(message)s&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;logging&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;basicConfig&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;format&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;format&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;level&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;logging&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;INFO&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                        &lt;span class=&quot;n&quot;&gt;datefmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;%H:%M:%S&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;database&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;FakeDatabase&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;logging&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;info&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;Testing update. Starting value is &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%d&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;.&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;database&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;concurrent&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;futures&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ThreadPoolExecutor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;max_workers&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;executor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;index&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;range&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;executor&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;submit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;database&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;update&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;logging&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;info&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;Testing update. Ending value is &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%d&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;.&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;database&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The program creates a &lt;code&gt;ThreadPoolExecutor&lt;/code&gt; with two threads and then calls &lt;code&gt;.submit()&lt;/code&gt; on each of them, telling them to run &lt;code&gt;database.update()&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;.submit()&lt;/code&gt; has a signature that allows both positional and named arguments to be passed to the function running in the thread:&lt;/p&gt;
&lt;div class=&quot;highlight python&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;submit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;kwargs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In the usage above, &lt;code&gt;index&lt;/code&gt; is passed as the first and only positional argument to &lt;code&gt;database.update()&lt;/code&gt;. You&amp;rsquo;ll see later in this article where you can pass multiple arguments in a similar manner.&lt;/p&gt;
&lt;p&gt;Since each thread runs &lt;code&gt;.update()&lt;/code&gt;, and &lt;code&gt;.update()&lt;/code&gt; adds one to &lt;code&gt;.value&lt;/code&gt;, you might expect &lt;code&gt;database.value&lt;/code&gt; to be &lt;code&gt;2&lt;/code&gt; when it&amp;rsquo;s printed out at the end. But you wouldn&amp;rsquo;t be looking at this example if that was the case. If you run the above code, the output looks like this:&lt;/p&gt;
&lt;div class=&quot;highlight sh&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; ./racecond.py
&lt;span class=&quot;go&quot;&gt;Testing unlocked update. Starting value is 0.&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Thread 0: starting update&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Thread 1: starting update&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Thread 0: finishing update&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Thread 1: finishing update&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Testing unlocked update. Ending value is 1.&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You might have expected that to happen, but let&amp;rsquo;s look at the details of what&amp;rsquo;s really going on here, as that will make the solution to this problem easier to understand.&lt;/p&gt;
&lt;h3 id=&quot;one-thread&quot;&gt;One Thread&lt;/h3&gt;
&lt;p&gt;Before you dive into this issue with two threads, let&amp;rsquo;s step back and talk a bit about some details of how threads work.&lt;/p&gt;
&lt;p&gt;You won&amp;rsquo;t be diving into all of the details here, as that&amp;rsquo;s not important at this level. We&amp;rsquo;ll also be simplifying a few things in a way that won&amp;rsquo;t be technically accurate but will give you the right idea of what is happening.&lt;/p&gt;
&lt;p&gt;When you tell your &lt;code&gt;ThreadPoolExecutor&lt;/code&gt; to run each thread, you tell it which function to run and what parameters to pass to it: &lt;code&gt;executor.submit(database.update, index)&lt;/code&gt;. &lt;/p&gt;
&lt;p&gt;The result of this is that each of the threads in the pool will call &lt;code&gt;database.update(index)&lt;/code&gt;. Note that &lt;code&gt;database&lt;/code&gt; is a reference to the one &lt;code&gt;FakeDatabase&lt;/code&gt; object created in &lt;code&gt;__main__&lt;/code&gt;. Calling &lt;code&gt;.update()&lt;/code&gt; on that object calls an &lt;a href=&quot;https://realpython.com/instance-class-and-static-methods-demystified/&quot;&gt;instance method&lt;/a&gt; on that object.&lt;/p&gt;
&lt;p&gt;Each thread is going to have a reference to the same &lt;code&gt;FakeDatabase&lt;/code&gt; object, &lt;code&gt;database&lt;/code&gt;. Each thread will also have a unique value, &lt;code&gt;index&lt;/code&gt;, to make the logging statements a bit easier to read:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://files.realpython.com/media/intro-threading-shared-database.267a5d8c6aa1.png&quot; target=&quot;_blank&quot;&gt;&lt;img class=&quot;img-fluid mx-auto d-block w-66&quot; src=&quot;https://files.realpython.com/media/intro-threading-shared-database.267a5d8c6aa1.png&quot; width=&quot;1623&quot; height=&quot;663&quot; srcset=&quot;https://robocrop.realpython.net/?url=https%3A//files.realpython.com/media/intro-threading-shared-database.267a5d8c6aa1.png&amp;amp;w=405&amp;amp;sig=a2cf6c8e812b6c948114c50b5402d51fb25ed155 405w, https://robocrop.realpython.net/?url=https%3A//files.realpython.com/media/intro-threading-shared-database.267a5d8c6aa1.png&amp;amp;w=811&amp;amp;sig=3708e9d6821e459c00fe576ffaa01cd2cab14b70 811w, https://files.realpython.com/media/intro-threading-shared-database.267a5d8c6aa1.png 1623w&quot; sizes=&quot;75vw&quot; alt=&quot;Thread 1 and Thread 2 use the same shared database.&quot;/&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;When the thread starts running &lt;code&gt;.update()&lt;/code&gt;, it has its own version of all of the data &lt;strong&gt;local&lt;/strong&gt; to the function. In the case of &lt;code&gt;.update()&lt;/code&gt;, this is &lt;code&gt;local_copy&lt;/code&gt;. This is definitely a good thing. Otherwise, two threads running the same function would always confuse each other. It means that all variables that are scoped (or local) to a function are &lt;strong&gt;thread-safe&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Now you can start walking through what happens if you run the program above with a single thread and a single call to &lt;code&gt;.update()&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The image below steps through the execution of &lt;code&gt;.update()&lt;/code&gt; if only a single thread is run. The statement is shown on the left followed by a diagram showing the values in the thread&amp;rsquo;s &lt;code&gt;local_value&lt;/code&gt; and the shared &lt;code&gt;database.value&lt;/code&gt;:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://files.realpython.com/media/intro-threading-single-thread.85204fa11210.png&quot; target=&quot;_blank&quot;&gt;&lt;img class=&quot;img-fluid mx-auto d-block w-66&quot; src=&quot;https://files.realpython.com/media/intro-threading-single-thread.85204fa11210.png&quot; width=&quot;1383&quot; height=&quot;2901&quot; srcset=&quot;https://robocrop.realpython.net/?url=https%3A//files.realpython.com/media/intro-threading-single-thread.85204fa11210.png&amp;amp;w=345&amp;amp;sig=3964a752874e9128c41941a52f9c7342e2f1e12a 345w, https://robocrop.realpython.net/?url=https%3A//files.realpython.com/media/intro-threading-single-thread.85204fa11210.png&amp;amp;w=691&amp;amp;sig=552252777e57ea21cc6aaa6ed39263aa1e60c1da 691w, https://files.realpython.com/media/intro-threading-single-thread.85204fa11210.png 1383w&quot; sizes=&quot;75vw&quot; alt=&quot;Single thread modifying a shared database&quot;/&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The diagram is laid out so that time increases as you move from top to bottom. It begins when &lt;code&gt;Thread 1&lt;/code&gt; is created and ends when it is terminated.&lt;/p&gt;
&lt;p&gt;When &lt;code&gt;Thread 1&lt;/code&gt; starts, &lt;code&gt;FakeDatabase.value&lt;/code&gt; is zero. The first line of code in the method, &lt;code&gt;local_copy = self.value&lt;/code&gt;, copies the value zero to the local variable. Next it increments the value of &lt;code&gt;local_copy&lt;/code&gt; with the &lt;code&gt;local_copy += 1&lt;/code&gt; statement. You can see &lt;code&gt;.value&lt;/code&gt; in &lt;code&gt;Thread 1&lt;/code&gt; getting set to one.&lt;/p&gt;
&lt;p&gt;Next &lt;code&gt;time.sleep()&lt;/code&gt; is called, which makes the current thread pause and allows other threads to run. Since there is only one thread in this example, this has no effect.&lt;/p&gt;
&lt;p&gt;When &lt;code&gt;Thread 1&lt;/code&gt; wakes up and continues, it copies the new value from &lt;code&gt;local_copy&lt;/code&gt; to &lt;code&gt;FakeDatabase.value&lt;/code&gt;, and then the thread is complete. You can see that &lt;code&gt;database.value&lt;/code&gt; is set to one.&lt;/p&gt;
&lt;p&gt;So far, so good. You ran &lt;code&gt;.update()&lt;/code&gt; once and &lt;code&gt;FakeDatabase.value&lt;/code&gt; was incremented to one.&lt;/p&gt;
&lt;h3 id=&quot;two-threads&quot;&gt;Two Threads&lt;/h3&gt;
&lt;p&gt;Getting back to the race condition, the two threads will be running concurrently but not at the same time. They will each have their own version of &lt;code&gt;local_copy&lt;/code&gt; and will each point to the same &lt;code&gt;database&lt;/code&gt;. It is this shared &lt;code&gt;database&lt;/code&gt; object that is going to cause the problems.&lt;/p&gt;
&lt;p&gt;The program starts with &lt;code&gt;Thread 1&lt;/code&gt; running &lt;code&gt;.update()&lt;/code&gt;:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://files.realpython.com/media/intro-threading-two-threads-part1.c1c0e65a8481.png&quot; target=&quot;_blank&quot;&gt;&lt;img class=&quot;img-fluid mx-auto d-block w-66&quot; src=&quot;https://files.realpython.com/media/intro-threading-two-threads-part1.c1c0e65a8481.png&quot; width=&quot;1953&quot; height=&quot;1641&quot; srcset=&quot;https://robocrop.realpython.net/?url=https%3A//files.realpython.com/media/intro-threading-two-threads-part1.c1c0e65a8481.png&amp;amp;w=488&amp;amp;sig=5a03e51ef3b111ab7525d287bfc56571927da0db 488w, https://robocrop.realpython.net/?url=https%3A//files.realpython.com/media/intro-threading-two-threads-part1.c1c0e65a8481.png&amp;amp;w=976&amp;amp;sig=fe92c3576eefae044f17a55010816e0d1c9ec240 976w, https://files.realpython.com/media/intro-threading-two-threads-part1.c1c0e65a8481.png 1953w&quot; sizes=&quot;75vw&quot; alt=&quot;Thread 1 gets a copy of shared data and increments it.&quot;/&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;When &lt;code&gt;Thread 1&lt;/code&gt; calls &lt;code&gt;time.sleep()&lt;/code&gt;, it allows the other thread to start running. This is where things get interesting.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Thread 2&lt;/code&gt; starts up and does the same operations. It&amp;rsquo;s also copying &lt;code&gt;database.value&lt;/code&gt; into its private &lt;code&gt;local_copy&lt;/code&gt;, and this shared &lt;code&gt;database.value&lt;/code&gt; has not yet been updated:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://files.realpython.com/media/intro-threading-two-threads-part2.df42d4fbfe21.png&quot; target=&quot;_blank&quot;&gt;&lt;img class=&quot;img-fluid mx-auto d-block w-66&quot; src=&quot;https://files.realpython.com/media/intro-threading-two-threads-part2.df42d4fbfe21.png&quot; width=&quot;2013&quot; height=&quot;1641&quot; srcset=&quot;https://robocrop.realpython.net/?url=https%3A//files.realpython.com/media/intro-threading-two-threads-part2.df42d4fbfe21.png&amp;amp;w=503&amp;amp;sig=469e3f134c8c24d34a4923a3afa7c4261b199935 503w, https://robocrop.realpython.net/?url=https%3A//files.realpython.com/media/intro-threading-two-threads-part2.df42d4fbfe21.png&amp;amp;w=1006&amp;amp;sig=59d3261bd00bf21276180b03684a5b36cc949c01 1006w, https://files.realpython.com/media/intro-threading-two-threads-part2.df42d4fbfe21.png 2013w&quot; sizes=&quot;75vw&quot; alt=&quot;Thread 2 gets a copy of shared data and increments it.&quot;/&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;When &lt;code&gt;Thread 2&lt;/code&gt; finally goes to sleep, the shared &lt;code&gt;database.value&lt;/code&gt; is still unmodified at zero, and both private versions of &lt;code&gt;local_copy&lt;/code&gt; have the value one.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Thread 1&lt;/code&gt; now wakes up and saves its version of &lt;code&gt;local_copy&lt;/code&gt; and then terminates, giving &lt;code&gt;Thread 2&lt;/code&gt; a final chance to run. &lt;code&gt;Thread 2&lt;/code&gt; has no idea that &lt;code&gt;Thread 1&lt;/code&gt; ran and updated &lt;code&gt;database.value&lt;/code&gt; while it was sleeping. It stores &lt;em&gt;its&lt;/em&gt; version of &lt;code&gt;local_copy&lt;/code&gt; into &lt;code&gt;database.value&lt;/code&gt;, also setting it to one:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://files.realpython.com/media/intro-threading-two-threads-part3.18576920f88f.png&quot; target=&quot;_blank&quot;&gt;&lt;img class=&quot;img-fluid mx-auto d-block w-66&quot; src=&quot;https://files.realpython.com/media/intro-threading-two-threads-part3.18576920f88f.png&quot; width=&quot;2013&quot; height=&quot;1551&quot; srcset=&quot;https://robocrop.realpython.net/?url=https%3A//files.realpython.com/media/intro-threading-two-threads-part3.18576920f88f.png&amp;amp;w=503&amp;amp;sig=3b11ef66873019a9edf48a7ff7445bc60d6daada 503w, https://robocrop.realpython.net/?url=https%3A//files.realpython.com/media/intro-threading-two-threads-part3.18576920f88f.png&amp;amp;w=1006&amp;amp;sig=bb0878750a37d23cfca07f30e95f289b1ee82770 1006w, https://files.realpython.com/media/intro-threading-two-threads-part3.18576920f88f.png 2013w&quot; sizes=&quot;75vw&quot; alt=&quot;Both threads write 1 to shared database.&quot;/&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The two threads have interleaving access to a single shared object, overwriting each other&amp;rsquo;s results. Similar race conditions can arise when one thread frees memory or closes a file handle before the other thread is finished accessing it.&lt;/p&gt;
&lt;h3 id=&quot;why-this-isnt-a-silly-example&quot;&gt;Why This Isn&amp;rsquo;t a Silly Example&lt;/h3&gt;
&lt;p&gt;The example above is contrived to make sure that the race condition happens every time you run your program. Because the operating system can swap out a thread at any time, it is possible to interrupt a statement like &lt;code&gt;x = x + 1&lt;/code&gt; after it has read the value of &lt;code&gt;x&lt;/code&gt; but before it has written back the incremented value.&lt;/p&gt;
&lt;p&gt;The details of how this happens are quite interesting, but not needed for the rest of this article, so feel free to skip over this hidden section.&lt;/p&gt;
&lt;div class=&quot;card mb-3&quot; id=&quot;collapse_carda9325a&quot;&gt;
&lt;div class=&quot;card-header border-0&quot;&gt;&lt;p class=&quot;m-0&quot;&gt;&lt;button class=&quot;btn&quot; data-toggle=&quot;collapse&quot; data-target=&quot;#collapsea9325a&quot; aria-expanded=&quot;false&quot; aria-controls=&quot;collapsea9325a&quot;&gt;How Does This Really Work&lt;/button&gt; &lt;button class=&quot;btn btn-link float-right&quot; data-toggle=&quot;collapse&quot; data-target=&quot;#collapsea9325a&quot; aria-expanded=&quot;false&quot; aria-controls=&quot;collapsea9325a&quot;&gt;Show/Hide&lt;/button&gt;&lt;/p&gt;&lt;/div&gt;
&lt;div id=&quot;collapsea9325a&quot; class=&quot;collapse&quot; data-parent=&quot;#collapse_carda9325a&quot;&gt;&lt;div class=&quot;card-body&quot; markdown=&quot;1&quot;&gt;

&lt;p&gt;The code above isn&amp;rsquo;t quite as out there as you might originally have thought. It was designed to force a race condition every time you run it, but that makes it much easier to solve than most race conditions.&lt;/p&gt;
&lt;p&gt;There are two things to keep in mind when thinking about race conditions:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Even an operation like &lt;code&gt;x += 1&lt;/code&gt; takes the processor many steps. Each of these steps is a separate instruction to the processor.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The operating system can swap which thread is running &lt;em&gt;at any time&lt;/em&gt;. A thread can be swapped out after any of these small instructions. This means that a thread can be put to sleep to let another thread run in the &lt;em&gt;middle&lt;/em&gt; of a Python statement.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Let&amp;rsquo;s look at this in detail. The REPL below shows a function that takes a parameter and increments it:&lt;/p&gt;
&lt;div class=&quot;highlight python pycon&quot;&gt;&lt;span class=&quot;repl-toggle&quot; title=&quot;Toggle REPL prompts and output&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;inc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;... &lt;/span&gt;   &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;...&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;dis&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dis&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dis&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;inc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  2           0 LOAD_FAST                0 (x)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;              2 LOAD_CONST               1 (1)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;              4 INPLACE_ADD&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;              6 STORE_FAST               0 (x)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;              8 LOAD_CONST               0 (None)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;             10 RETURN_VALUE&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The REPL example uses &lt;a href=&quot;https://docs.python.org/3/library/dis.html&quot;&gt;&lt;code&gt;dis&lt;/code&gt;&lt;/a&gt; from the Python standard library to show the smaller steps that the processor does to implement your function. It does a &lt;code&gt;LOAD_FAST&lt;/code&gt; of the data value &lt;code&gt;x&lt;/code&gt;, it does a &lt;code&gt;LOAD_CONST 1&lt;/code&gt;, and then it uses the &lt;code&gt;INPLACE_ADD&lt;/code&gt; to add those values together.&lt;/p&gt;
&lt;p&gt;We&amp;rsquo;re stopping here for a specific reason. This is the point in &lt;code&gt;.update()&lt;/code&gt; above where &lt;code&gt;time.sleep()&lt;/code&gt; forced the threads to switch. It is entirely possible that, every once in while, the operating system would switch threads at that exact point even without &lt;code&gt;sleep()&lt;/code&gt;, but the call to &lt;code&gt;sleep()&lt;/code&gt; makes it happen every time.&lt;/p&gt;
&lt;p&gt;As you learned above, the operating system can swap threads at any time. You&amp;rsquo;ve walked down this listing to the statement marked &lt;code&gt;4&lt;/code&gt;. If the operating system swaps out this thread and runs a different thread that also modifies &lt;code&gt;x&lt;/code&gt;, then when this thread resumes, it will overwrite &lt;code&gt;x&lt;/code&gt; with an incorrect value.&lt;/p&gt;
&lt;p&gt;Technically, this example won&amp;rsquo;t have a race condition because &lt;code&gt;x&lt;/code&gt; is local to &lt;code&gt;inc()&lt;/code&gt;. It does illustrate how a thread can be interrupted during a single Python operation, however. The same LOAD, MODIFY, STORE set of operations also happens on global and shared values. You can explore with the &lt;code&gt;dis&lt;/code&gt; module and prove that yourself.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s rare to get a race condition like this to occur, but remember that an infrequent event taken over millions of iterations becomes likely to happen. The rarity of these race conditions makes them much, much harder to debug than regular bugs.&lt;/p&gt;
&lt;p&gt;Now back to your regularly scheduled tutorial!&lt;/p&gt;
&lt;/div&gt;&lt;/div&gt;

&lt;/div&gt;
&lt;p&gt;Now that you&amp;rsquo;ve seen a race condition in action, let&amp;rsquo;s find out how to solve them!&lt;/p&gt;
&lt;h2 id=&quot;basic-synchronization-using-lock&quot;&gt;Basic Synchronization Using &lt;code&gt;Lock&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;There are a number of ways to avoid or solve race conditions. You won&amp;rsquo;t look at all of them here, but there are a couple that are used frequently. Let&amp;rsquo;s start with &lt;code&gt;Lock&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;To solve your race condition above, you need to find a way to allow only one thread at a time into the read-modify-write section of your code. The most common way to do this is called &lt;code&gt;Lock&lt;/code&gt; in Python. In some other languages this same idea is called  a &lt;code&gt;mutex&lt;/code&gt;. Mutex comes from MUTual EXclusion, which is exactly what a &lt;code&gt;Lock&lt;/code&gt; does.&lt;/p&gt;
&lt;p&gt;A &lt;code&gt;Lock&lt;/code&gt; is an object that acts like a hall pass. Only one thread at a time can have the &lt;code&gt;Lock&lt;/code&gt;. Any other thread that wants the &lt;code&gt;Lock&lt;/code&gt; must wait until the owner of the &lt;code&gt;Lock&lt;/code&gt; gives it up.&lt;/p&gt;
&lt;p&gt;The basic functions to do this are &lt;code&gt;.acquire()&lt;/code&gt; and &lt;code&gt;.release()&lt;/code&gt;. A thread will call &lt;code&gt;my_lock.acquire()&lt;/code&gt; to get the lock. If the lock is already held, the calling thread will wait until it is released. There&amp;rsquo;s an important point here. If one thread gets the lock but never gives it back, your program will be stuck. You&amp;rsquo;ll read more about this later.&lt;/p&gt;
&lt;p&gt;Fortunately, Python&amp;rsquo;s &lt;code&gt;Lock&lt;/code&gt; will also operate as a context manager, so you can use it in a &lt;code&gt;with&lt;/code&gt; statement, and it gets released automatically when the &lt;code&gt;with&lt;/code&gt; block exits for any reason.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s look at the &lt;code&gt;FakeDatabase&lt;/code&gt; with a &lt;code&gt;Lock&lt;/code&gt; added to it. The calling function stays the same:&lt;/p&gt;
&lt;div class=&quot;highlight python&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;FakeDatabase&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;__init__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_lock&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;threading&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Lock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;locked_update&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;logging&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;info&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;Thread &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%s&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;: starting update&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;logging&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;debug&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;Thread &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%s&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; about to lock&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_lock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;logging&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;debug&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;Thread &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%s&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; has lock&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;local_copy&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;local_copy&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sleep&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;local_copy&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;logging&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;debug&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;Thread &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%s&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; about to release lock&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;logging&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;debug&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;Thread &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%s&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; after release&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;logging&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;info&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;Thread &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%s&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;: finishing update&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Other than adding a bunch of debug logging so you can see the locking more clearly, the big change here is to add a member called &lt;code&gt;._lock&lt;/code&gt;, which is a &lt;code&gt;threading.Lock()&lt;/code&gt; object. This &lt;code&gt;._lock&lt;/code&gt; is initialized in the unlocked state and locked and released by the &lt;code&gt;with&lt;/code&gt; statement.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s worth noting here that the thread running this function will hold on to that &lt;code&gt;Lock&lt;/code&gt; until it is completely finished updating the database. In this case, that means it will hold the &lt;code&gt;Lock&lt;/code&gt; while it copies, updates, sleeps, and then writes the value back to the database.&lt;/p&gt;
&lt;p&gt;If you run this version with logging set to warning level, you&amp;rsquo;ll see this:&lt;/p&gt;
&lt;div class=&quot;highlight sh&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; ./fixrace.py
&lt;span class=&quot;go&quot;&gt;Testing locked update. Starting value is 0.&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Thread 0: starting update&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Thread 1: starting update&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Thread 0: finishing update&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Thread 1: finishing update&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Testing locked update. Ending value is 2.&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Look at that. Your program finally works!&lt;/p&gt;
&lt;p&gt;You can turn on full logging by setting the level to &lt;code&gt;DEBUG&lt;/code&gt; by adding this statement after you configure the logging output in &lt;code&gt;__main__&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight python&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;logging&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;getLogger&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;setLevel&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;logging&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;DEBUG&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Running this program with &lt;code&gt;DEBUG&lt;/code&gt; logging turned on looks like this:&lt;/p&gt;
&lt;div class=&quot;highlight sh&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; ./fixrace.py
&lt;span class=&quot;go&quot;&gt;Testing locked update. Starting value is 0.&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Thread 0: starting update&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Thread 0 about to lock&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Thread 0 has lock&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Thread 1: starting update&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Thread 1 about to lock&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Thread 0 about to release lock&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Thread 0 after release&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Thread 0: finishing update&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Thread 1 has lock&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Thread 1 about to release lock&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Thread 1 after release&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Thread 1: finishing update&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Testing locked update. Ending value is 2.&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In this output you can see &lt;code&gt;Thread 0&lt;/code&gt; acquires the lock and is still holding it when it goes to sleep. &lt;code&gt;Thread 1&lt;/code&gt; then starts and attempts to acquire the same lock. Because &lt;code&gt;Thread 0&lt;/code&gt; is still holding it, &lt;code&gt;Thread 1&lt;/code&gt; has to wait. This is the mutual exclusion that a &lt;code&gt;Lock&lt;/code&gt; provides.&lt;/p&gt;
&lt;p&gt;Many of the examples in the rest of this article will have &lt;code&gt;WARNING&lt;/code&gt; and &lt;code&gt;DEBUG&lt;/code&gt; level logging. We&amp;rsquo;ll generally only show the &lt;code&gt;WARNING&lt;/code&gt; level output, as the &lt;code&gt;DEBUG&lt;/code&gt; logs can be quite lengthy. Try out the programs with the logging turned up and see what they do.&lt;/p&gt;
&lt;h2 id=&quot;deadlock&quot;&gt;Deadlock&lt;/h2&gt;
&lt;p&gt;Before you move on, you should look at a common problem when using &lt;code&gt;Locks&lt;/code&gt;. As you saw, if the &lt;code&gt;Lock&lt;/code&gt; has already been acquired, a second call to &lt;code&gt;.acquire()&lt;/code&gt; will wait until the thread that is holding the &lt;code&gt;Lock&lt;/code&gt; calls &lt;code&gt;.release()&lt;/code&gt;. What do you think happens when you run this code:&lt;/p&gt;
&lt;div class=&quot;highlight python&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;threading&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;l&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;threading&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Lock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;before first acquire&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;acquire&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;before second acquire&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;acquire&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;acquired lock twice&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;When the program calls &lt;code&gt;l.acquire()&lt;/code&gt; the second time, it hangs waiting for the &lt;code&gt;Lock&lt;/code&gt; to be released. In this example, you can fix the deadlock by removing the second call, but deadlocks usually happen from one of two subtle things:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;An implementation bug where a &lt;code&gt;Lock&lt;/code&gt; is not released properly&lt;/li&gt;
&lt;li&gt;A design issue where a utility function needs to be called by functions that might or might not already have the &lt;code&gt;Lock&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The first situation happens sometimes, but using a &lt;code&gt;Lock&lt;/code&gt; as a context manager greatly reduces how often. It is recommended to write code whenever possible to make use of context managers, as they help to avoid situations where an exception skips you over the &lt;code&gt;.release()&lt;/code&gt; call.&lt;/p&gt;
&lt;p&gt;The design issue can be a bit trickier in some languages. Thankfully, Python threading has a second object, called &lt;code&gt;RLock&lt;/code&gt;, that is designed for just this situation. It allows a thread to &lt;code&gt;.acquire()&lt;/code&gt; an &lt;code&gt;RLock&lt;/code&gt; multiple times before it calls &lt;code&gt;.release()&lt;/code&gt;. That thread is still required to call &lt;code&gt;.release()&lt;/code&gt; the same number of times it called &lt;code&gt;.acquire()&lt;/code&gt;, but it should be doing that anyway.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Lock&lt;/code&gt; and &lt;code&gt;RLock&lt;/code&gt; are two of the basic tools used in threaded programming to prevent race conditions. There are a few other that work in different ways. Before you look at them, let&amp;rsquo;s shift to a slightly different problem domain.&lt;/p&gt;
&lt;h2 id=&quot;producer-consumer-threading&quot;&gt;Producer-Consumer Threading&lt;/h2&gt;
&lt;p&gt;The &lt;a href=&quot;https://en.wikipedia.org/wiki/Producer%E2%80%93consumer_problem&quot;&gt;Producer-Consumer Problem&lt;/a&gt; is a standard computer science problem used to look at threading or process synchronization issues. You&amp;rsquo;re going to look at a variant of it to get some ideas of what primitives the Python &lt;code&gt;threading&lt;/code&gt; module provides.&lt;/p&gt;
&lt;p&gt;For this example, you&amp;rsquo;re going to imagine a program that needs to read messages from a network and write them to disk. The program does not request a message when it wants. It must be listening and accept messages as they come in. The messages will not come in at a regular pace, but will be coming in bursts. This part of the program is called the producer.&lt;/p&gt;
&lt;p&gt;On the other side, once you have a message, you need to write it to a database. The database access is slow, but fast enough to keep up to the average pace of messages. It is &lt;em&gt;not&lt;/em&gt; fast enough to keep up when a burst of messages comes in. This part is the consumer.&lt;/p&gt;
&lt;p&gt;In between the producer and the consumer, you will create a &lt;code&gt;Pipeline&lt;/code&gt; that will be the part that changes as you learn about different synchronization objects.&lt;/p&gt;
&lt;p&gt;That&amp;rsquo;s the basic layout. Let&amp;rsquo;s look at a solution using &lt;code&gt;Lock&lt;/code&gt;. It doesn&amp;rsquo;t work perfectly, but it uses tools you already know, so it&amp;rsquo;s a good place to start.&lt;/p&gt;
&lt;h3 id=&quot;producer-consumer-using-lock&quot;&gt;Producer-Consumer Using &lt;code&gt;Lock&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;Since this is an article about Python &lt;code&gt;threading&lt;/code&gt;, and since you just read about the &lt;code&gt;Lock&lt;/code&gt; primitive, let&amp;rsquo;s try to solve this problem with two threads using a &lt;code&gt;Lock&lt;/code&gt; or two.&lt;/p&gt;
&lt;p&gt;The general design is that there is a &lt;code&gt;producer&lt;/code&gt; thread that reads from the fake network and puts the message into a &lt;code&gt;Pipeline&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight python&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SENTINEL&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;object&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;producer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pipeline&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;sd&quot;&gt;&amp;quot;&amp;quot;&amp;quot;Pretend we&amp;#39;re getting a message from the network.&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;index&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;range&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;message&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;random&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;randint&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;101&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;logging&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;info&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;Producer got message: &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%s&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;pipeline&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;set_message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;Producer&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;# Send a sentinel message to tell consumer we&amp;#39;re done&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;pipeline&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;set_message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SENTINEL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;Producer&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;To generate a fake message, the &lt;code&gt;producer&lt;/code&gt; gets a random number between one and one hundred. It calls &lt;code&gt;.set_message()&lt;/code&gt; on the &lt;code&gt;pipeline&lt;/code&gt; to send it to the &lt;code&gt;consumer&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;producer&lt;/code&gt; also  uses a &lt;code&gt;SENTINEL&lt;/code&gt; value to signal the consumer to stop after it has sent ten values. This is a little awkward, but don&amp;rsquo;t worry, you&amp;rsquo;ll see ways to get rid of this &lt;code&gt;SENTINEL&lt;/code&gt; value after you work through this example.&lt;/p&gt;
&lt;p&gt;On the other side of the &lt;code&gt;pipeline&lt;/code&gt; is the consumer:&lt;/p&gt;
&lt;div class=&quot;highlight python&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;consumer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pipeline&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;sd&quot;&gt;&amp;quot;&amp;quot;&amp;quot;Pretend we&amp;#39;re saving a number in the database.&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;message&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;message&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SENTINEL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;message&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pipeline&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get_message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;Consumer&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;message&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SENTINEL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;logging&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;info&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;Consumer storing message: &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%s&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;consumer&lt;/code&gt; reads a message from the &lt;code&gt;pipeline&lt;/code&gt; and writes it to a fake database, which in this case is just printing it to the display. If it gets the &lt;code&gt;SENTINEL&lt;/code&gt; value, it returns from the function, which will terminate the thread.&lt;/p&gt;
&lt;p&gt;Before you look at the really interesting part, the &lt;code&gt;Pipeline&lt;/code&gt;, here&amp;rsquo;s the &lt;code&gt;__main__&lt;/code&gt; section, which spawns these threads:&lt;/p&gt;
&lt;div class=&quot;highlight python&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;vm&quot;&gt;__name__&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;__main__&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;format&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%(asctime)s&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%(message)s&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;logging&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;basicConfig&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;format&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;format&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;level&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;logging&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;INFO&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                        &lt;span class=&quot;n&quot;&gt;datefmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;%H:%M:%S&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# logging.getLogger().setLevel(logging.DEBUG)&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;pipeline&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Pipeline&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;concurrent&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;futures&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ThreadPoolExecutor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;max_workers&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;executor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;executor&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;submit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;producer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pipeline&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;executor&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;submit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;consumer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pipeline&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This should look fairly familiar as it&amp;rsquo;s close to the &lt;code&gt;__main__&lt;/code&gt; code in the previous examples.&lt;/p&gt;
&lt;p&gt;Remember that you can turn on &lt;code&gt;DEBUG&lt;/code&gt; logging to see all of the logging messages by uncommenting  this line:&lt;/p&gt;
&lt;div class=&quot;highlight python&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;# logging.getLogger().setLevel(logging.DEBUG)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;It can be worthwhile to walk through the &lt;code&gt;DEBUG&lt;/code&gt; logging messages to see exactly where each thread acquires and releases the locks.&lt;/p&gt;
&lt;p&gt;Now let&amp;rsquo;s take a look at the &lt;code&gt;Pipeline&lt;/code&gt; that passes messages from the &lt;code&gt;producer&lt;/code&gt; to the &lt;code&gt;consumer&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight python&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Pipeline&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;sd&quot;&gt;&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;span class=&quot;sd&quot;&gt;    Class to allow a single element pipeline between producer and consumer.&lt;/span&gt;
&lt;span class=&quot;sd&quot;&gt;    &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;__init__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;message&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;producer_lock&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;threading&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Lock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;consumer_lock&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;threading&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Lock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;consumer_lock&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;acquire&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;get_message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;logging&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;debug&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%s&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;:about to acquire getlock&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;consumer_lock&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;acquire&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;logging&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;debug&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%s&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;:have getlock&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;message&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;message&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;logging&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;debug&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%s&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;:about to release setlock&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;producer_lock&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;release&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;logging&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;debug&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%s&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;:setlock released&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;message&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;set_message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;logging&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;debug&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%s&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;:about to acquire setlock&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;producer_lock&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;acquire&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;logging&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;debug&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%s&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;:have setlock&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;message&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;message&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;logging&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;debug&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%s&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;:about to release getlock&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;consumer_lock&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;release&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;logging&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;debug&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%s&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;:getlock released&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Woah! That&amp;rsquo;s a lot of code. A pretty high percentage of that is just logging statements to make it easier to see what&amp;rsquo;s happening when you run it. Here&amp;rsquo;s the same code with all of the logging statements removed:&lt;/p&gt;
&lt;div class=&quot;highlight python&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Pipeline&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;sd&quot;&gt;&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;span class=&quot;sd&quot;&gt;    Class to allow a single element pipeline between producer and consumer.&lt;/span&gt;
&lt;span class=&quot;sd&quot;&gt;    &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;__init__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;message&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;producer_lock&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;threading&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Lock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;consumer_lock&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;threading&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Lock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;consumer_lock&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;acquire&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;get_message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;consumer_lock&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;acquire&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;message&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;message&lt;/span&gt;
        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;producer_lock&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;release&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;message&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;set_message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;producer_lock&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;acquire&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;message&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;message&lt;/span&gt;
        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;consumer_lock&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;release&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;That seems a bit more manageable. The &lt;code&gt;Pipeline&lt;/code&gt; in this version of your code has three members:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;.message&lt;/code&gt;&lt;/strong&gt; stores the message to pass.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;.producer_lock&lt;/code&gt;&lt;/strong&gt; is a &lt;code&gt;threading.Lock&lt;/code&gt; object that restricts access to the message by the &lt;code&gt;producer&lt;/code&gt; thread.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;.consumer_lock&lt;/code&gt;&lt;/strong&gt; is also a &lt;code&gt;threading.Lock&lt;/code&gt; that restricts access to the message by the &lt;code&gt;consumer&lt;/code&gt; thread.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;code&gt;__init__()&lt;/code&gt; initializes these three members and then calls &lt;code&gt;.acquire()&lt;/code&gt; on the &lt;code&gt;.consumer_lock&lt;/code&gt;. This is the state you want to start in. The &lt;code&gt;producer&lt;/code&gt; is allowed to add a new message, but the &lt;code&gt;consumer&lt;/code&gt; needs to wait until a message is present.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;.get_message()&lt;/code&gt; and &lt;code&gt;.set_messages()&lt;/code&gt; are nearly opposites. &lt;code&gt;.get_message()&lt;/code&gt; calls &lt;code&gt;.acquire()&lt;/code&gt; on the &lt;code&gt;consumer_lock&lt;/code&gt;. This is the call that will make the &lt;code&gt;consumer&lt;/code&gt; wait until a message is ready.&lt;/p&gt;
&lt;p&gt;Once the &lt;code&gt;consumer&lt;/code&gt; has acquired the &lt;code&gt;.consumer_lock&lt;/code&gt;, it copies out the value in &lt;code&gt;.message&lt;/code&gt; and then calls &lt;code&gt;.release()&lt;/code&gt; on the &lt;code&gt;.producer_lock&lt;/code&gt;. Releasing this lock is what allows the &lt;code&gt;producer&lt;/code&gt; to insert the next message into the &lt;code&gt;pipeline&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Before you go on to &lt;code&gt;.set_message()&lt;/code&gt;, there&amp;rsquo;s something subtle going on in &lt;code&gt;.get_message()&lt;/code&gt; that&amp;rsquo;s pretty easy to miss. It might seem tempting to get rid of &lt;code&gt;message&lt;/code&gt; and just have the function end with &lt;code&gt;return self.message&lt;/code&gt;. See if you can figure out why you don&amp;rsquo;t want to do that before moving on.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s the answer. As soon as the &lt;code&gt;consumer&lt;/code&gt; calls &lt;code&gt;.producer_lock.release()&lt;/code&gt;, it can be swapped out, and the &lt;code&gt;producer&lt;/code&gt; can start running. That could happen before &lt;code&gt;.release()&lt;/code&gt; returns! This means that there is a slight possibility that when the function returns &lt;code&gt;self.message&lt;/code&gt;, that could actually be the &lt;em&gt;next&lt;/em&gt; message generated, so you would lose the first message. This is another example of a race condition.&lt;/p&gt;
&lt;p&gt;Moving on to &lt;code&gt;.set_message()&lt;/code&gt;, you can see the opposite side of the transaction. The &lt;code&gt;producer&lt;/code&gt; will call this with a message. It will acquire the &lt;code&gt;.producer_lock&lt;/code&gt;, set the &lt;code&gt;.message&lt;/code&gt;, and the call &lt;code&gt;.release()&lt;/code&gt; on then &lt;code&gt;consumer_lock&lt;/code&gt;, which will allow the &lt;code&gt;consumer&lt;/code&gt; to read that value.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s run the code that has logging set to &lt;code&gt;WARNING&lt;/code&gt; and see what it looks like:&lt;/p&gt;
&lt;div class=&quot;highlight sh&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; ./prodcom_lock.py
&lt;span class=&quot;go&quot;&gt;Producer got data 43&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Producer got data 45&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Consumer storing data: 43&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Producer got data 86&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Consumer storing data: 45&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Producer got data 40&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Consumer storing data: 86&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Producer got data 62&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Consumer storing data: 40&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Producer got data 15&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Consumer storing data: 62&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Producer got data 16&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Consumer storing data: 15&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Producer got data 61&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Consumer storing data: 16&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Producer got data 73&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Consumer storing data: 61&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Producer got data 22&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Consumer storing data: 73&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Consumer storing data: 22&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;At first, you might find it odd that the producer gets two messages before the consumer even runs. If you look back at the &lt;code&gt;producer&lt;/code&gt; and &lt;code&gt;.set_message()&lt;/code&gt;, you will notice that the only place it will wait for a &lt;code&gt;Lock&lt;/code&gt; is when it attempts to put the message into the pipeline. This is done after the &lt;code&gt;producer&lt;/code&gt; gets the message and logs that it has it.&lt;/p&gt;
&lt;p&gt;When the &lt;code&gt;producer&lt;/code&gt; attempts to send this second message, it will call &lt;code&gt;.set_message()&lt;/code&gt; the second time and it will block.&lt;/p&gt;
&lt;p&gt;The operating system can swap threads at any time, but it generally lets each thread have a reasonable amount of time to run before swapping it out. That&amp;rsquo;s why the &lt;code&gt;producer&lt;/code&gt; usually runs until it blocks in the second call to &lt;code&gt;.set_message()&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Once a thread is blocked, however, the operating system will always swap it out and find a different thread to run. In this case, the only other thread with anything to do is the &lt;code&gt;consumer&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;consumer&lt;/code&gt; calls &lt;code&gt;.get_message()&lt;/code&gt;, which reads the message and calls &lt;code&gt;.release()&lt;/code&gt; on the &lt;code&gt;.producer_lock&lt;/code&gt;, thus allowing the &lt;code&gt;producer&lt;/code&gt; to run again the next time threads are swapped.&lt;/p&gt;
&lt;p&gt;Notice that the first message was &lt;code&gt;43&lt;/code&gt;, and that is exactly what the &lt;code&gt;consumer&lt;/code&gt; read, even though the &lt;code&gt;producer&lt;/code&gt; had already generated the &lt;code&gt;45&lt;/code&gt; message.&lt;/p&gt;
&lt;p&gt;While it works for this limited test, it is not a great solution to the producer-consumer problem in general because it only allows a single value in the pipeline at a time. When the &lt;code&gt;producer&lt;/code&gt; gets a burst of messages, it will have nowhere to put them.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s move on to a better way to solve this problem, using a &lt;code&gt;Queue&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;producer-consumer-using-queue&quot;&gt;Producer-Consumer Using &lt;code&gt;Queue&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;If you want to be able to handle more than one value in the pipeline at a time, you&amp;rsquo;ll need a data structure for the pipeline that allows the number to grow and shrink as data backs up from the &lt;code&gt;producer&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Python&amp;rsquo;s standard library has a &lt;code&gt;queue&lt;/code&gt; module which, in turn, has a &lt;code&gt;Queue&lt;/code&gt; class. Let&amp;rsquo;s change the &lt;code&gt;Pipeline&lt;/code&gt; to use a &lt;code&gt;Queue&lt;/code&gt; instead of just a variable protected by a &lt;code&gt;Lock&lt;/code&gt;. You&amp;rsquo;ll also use a different way to stop the worker threads by using a different primitive from Python &lt;code&gt;threading&lt;/code&gt;, an &lt;code&gt;Event&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s start with the &lt;code&gt;Event&lt;/code&gt;. The &lt;code&gt;threading.Event&lt;/code&gt; object allows one thread to signal an &lt;code&gt;event&lt;/code&gt; while many other threads can be waiting for that &lt;code&gt;event&lt;/code&gt; to happen. The key usage in this code is that the threads that are waiting for the event do not necessarily need to stop what they are doing, they can just check the status of the &lt;code&gt;Event&lt;/code&gt; every once in a while.&lt;/p&gt;
&lt;p&gt;The triggering of the event can be many things. In this example, the main thread will simply sleep for a while and then &lt;code&gt;.set()&lt;/code&gt; it:&lt;/p&gt;
&lt;div class=&quot;highlight python&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;lineno&quot;&gt; 1 &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;vm&quot;&gt;__name__&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;__main__&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 2 &lt;/span&gt;    &lt;span class=&quot;nb&quot;&gt;format&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%(asctime)s&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%(message)s&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 3 &lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;logging&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;basicConfig&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;format&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;format&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;level&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;logging&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;INFO&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 4 &lt;/span&gt;                        &lt;span class=&quot;n&quot;&gt;datefmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;%H:%M:%S&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 5 &lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;# logging.getLogger().setLevel(logging.DEBUG)&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 6 &lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 7 &lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;pipeline&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Pipeline&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 8 &lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;event&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;threading&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Event&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 9 &lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;concurrent&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;futures&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ThreadPoolExecutor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;max_workers&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;executor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;10 &lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;executor&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;submit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;producer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pipeline&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;11 &lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;executor&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;submit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;consumer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pipeline&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;12 &lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;13 &lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sleep&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;14 &lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;logging&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;info&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;Main: about to set event&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;15 &lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The only changes here are the creation of the &lt;code&gt;event&lt;/code&gt; object on line 6, passing the &lt;code&gt;event&lt;/code&gt; as a parameter on lines 8 and 9, and the final section on lines 11 to 13, which sleep for a second, log a message, and then call &lt;code&gt;.set()&lt;/code&gt; on the event.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;producer&lt;/code&gt; also did not have to change too much:&lt;/p&gt;
&lt;div class=&quot;highlight python&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;lineno&quot;&gt; 1 &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;producer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pipeline&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 2 &lt;/span&gt;    &lt;span class=&quot;sd&quot;&gt;&amp;quot;&amp;quot;&amp;quot;Pretend we&amp;#39;re getting a number from the network.&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 3 &lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;is_set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 4 &lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;message&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;random&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;randint&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;101&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 5 &lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;logging&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;info&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;Producer got message: &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%s&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 6 &lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;pipeline&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;set_message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;Producer&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 7 &lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 8 &lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;logging&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;info&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;Producer received EXIT event. Exiting&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;It now will loop until it sees that the event was set on line 3. It also no longer puts the &lt;code&gt;SENTINEL&lt;/code&gt; value into the &lt;code&gt;pipeline&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;consumer&lt;/code&gt; had to change a little more:&lt;/p&gt;
&lt;div class=&quot;highlight python&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;lineno&quot;&gt; 1 &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;consumer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pipeline&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 2 &lt;/span&gt;    &lt;span class=&quot;sd&quot;&gt;&amp;quot;&amp;quot;&amp;quot;Pretend we&amp;#39;re saving a number in the database.&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 3 &lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;is_set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pipeline&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;empty&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 4 &lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;message&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pipeline&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get_message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;Consumer&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 5 &lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;logging&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;info&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 6 &lt;/span&gt;            &lt;span class=&quot;s2&quot;&gt;&amp;quot;Consumer storing message: &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%s&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;  (queue size=&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%s&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;)&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 7 &lt;/span&gt;            &lt;span class=&quot;n&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 8 &lt;/span&gt;            &lt;span class=&quot;n&quot;&gt;pipeline&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;qsize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 9 &lt;/span&gt;        &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;10 &lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;11 &lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;logging&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;info&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;Consumer received EXIT event. Exiting&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;While you got to take out the code related to the &lt;code&gt;SENTINEL&lt;/code&gt; value, you did have to do a slightly more complicated &lt;code&gt;while&lt;/code&gt; condition. Not only does it loop until the &lt;code&gt;event&lt;/code&gt; is set, but it also needs to keep looping until the &lt;code&gt;pipeline&lt;/code&gt; has been emptied.&lt;/p&gt;
&lt;p&gt;Making sure the queue is empty before the consumer finishes prevents another fun issue. If the &lt;code&gt;consumer&lt;/code&gt; does exit while the &lt;code&gt;pipeline&lt;/code&gt; has messages in it, there are two bad things that can happen. The first is that you lose those final messages, but the more serious one is that the &lt;code&gt;producer&lt;/code&gt; can get caught on the &lt;code&gt;producer_lock&lt;/code&gt; and never return.&lt;/p&gt;
&lt;p&gt;This happens if the &lt;code&gt;event&lt;/code&gt; gets triggered after the &lt;code&gt;producer&lt;/code&gt; has checked the &lt;code&gt;.is_set()&lt;/code&gt; condition but before it calls &lt;code&gt;pipeline.set_message()&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;If that happens, it&amp;rsquo;s possible for the producer to wake up and exit with the &lt;code&gt;.producer_lock&lt;/code&gt; still being held. The &lt;code&gt;producer&lt;/code&gt; will then try to &lt;code&gt;.acquire()&lt;/code&gt; the &lt;code&gt;.producer_lock&lt;/code&gt;, but the &lt;code&gt;consumer&lt;/code&gt; has exited and will never &lt;code&gt;.release()&lt;/code&gt; it.&lt;/p&gt;
&lt;p&gt;The rest of the &lt;code&gt;consumer&lt;/code&gt; should look familiar.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;Pipeline&lt;/code&gt; has changed dramatically, however:&lt;/p&gt;
&lt;div class=&quot;highlight python&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;lineno&quot;&gt; 1 &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Pipeline&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;queue&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Queue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 2 &lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;__init__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 3 &lt;/span&gt;        &lt;span class=&quot;nb&quot;&gt;super&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;fm&quot;&gt;__init__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;maxsize&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 4 &lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 5 &lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;get_message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 6 &lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;logging&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;debug&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%s&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;:about to get from queue&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 7 &lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 8 &lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;logging&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;debug&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%s&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;:got &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%d&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; from queue&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 9 &lt;/span&gt;        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;10 &lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;11 &lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;set_message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;12 &lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;logging&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;debug&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%s&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;:about to add &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%d&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; to queue&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;13 &lt;/span&gt;        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;put&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;14 &lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;logging&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;debug&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%s&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;:added &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%d&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; to queue&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You can see that &lt;code&gt;Pipeline&lt;/code&gt; is a subclass of &lt;code&gt;queue.Queue&lt;/code&gt;. &lt;code&gt;Queue&lt;/code&gt; has an optional parameter when initializing to specify a maximum size of the queue.&lt;/p&gt;
&lt;p&gt;If you give a positive number for &lt;code&gt;maxsize&lt;/code&gt;, it will limit the queue to that number of elements, causing &lt;code&gt;.put()&lt;/code&gt; to block until there are fewer than &lt;code&gt;maxsize&lt;/code&gt; elements. If you don&amp;rsquo;t specify &lt;code&gt;maxsize&lt;/code&gt;, then the queue will grow to the limits of your computer&amp;rsquo;s memory.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;.get_message()&lt;/code&gt; and &lt;code&gt;.set_message()&lt;/code&gt; got much smaller. They basically wrap &lt;code&gt;.get()&lt;/code&gt; and &lt;code&gt;.put()&lt;/code&gt; on the &lt;code&gt;Queue&lt;/code&gt;. You might be wondering where all of the locking code that prevents the threads from causing race conditions went.&lt;/p&gt;
&lt;p&gt;The core devs who wrote the standard library knew that a &lt;code&gt;Queue&lt;/code&gt; is frequently used in multi-threading environments and incorporated all of that locking code inside the &lt;code&gt;Queue&lt;/code&gt; itself. &lt;code&gt;Queue&lt;/code&gt; is thread-safe.&lt;/p&gt;
&lt;p&gt;Running this program looks like the following:&lt;/p&gt;
&lt;div class=&quot;highlight sh&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; ./prodcom_queue.py
&lt;span class=&quot;go&quot;&gt;Producer got message: 32&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Producer got message: 51&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Producer got message: 25&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Producer got message: 94&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Producer got message: 29&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Consumer storing message: 32 (queue size=3)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Producer got message: 96&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Consumer storing message: 51 (queue size=3)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Producer got message: 6&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Consumer storing message: 25 (queue size=3)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Producer got message: 31&lt;/span&gt;

&lt;span class=&quot;go&quot;&gt;[many lines deleted]&lt;/span&gt;

&lt;span class=&quot;go&quot;&gt;Producer got message: 80&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Consumer storing message: 94 (queue size=6)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Producer got message: 33&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Consumer storing message: 20 (queue size=6)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Producer got message: 48&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Consumer storing message: 31 (queue size=6)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Producer got message: 52&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Consumer storing message: 98 (queue size=6)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Main: about to set event&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Producer got message: 13&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Consumer storing message: 59 (queue size=6)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Producer received EXIT event. Exiting&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Consumer storing message: 75 (queue size=6)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Consumer storing message: 97 (queue size=5)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Consumer storing message: 80 (queue size=4)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Consumer storing message: 33 (queue size=3)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Consumer storing message: 48 (queue size=2)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Consumer storing message: 52 (queue size=1)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Consumer storing message: 13 (queue size=0)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Consumer received EXIT event. Exiting&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;If you read through the output in my example, you can see some interesting things happening. Right at the top, you can see the &lt;code&gt;producer&lt;/code&gt; got to create five messages and place four of them on the queue. It got swapped out by the operating system before it could place the fifth one.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;consumer&lt;/code&gt; then ran and pulled off the first message. It printed out that message as well as how deep the queue was at that point:&lt;/p&gt;
&lt;div class=&quot;highlight sh&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;go&quot;&gt;Consumer storing message: 32 (queue size=3)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This is how you know that the fifth message hasn&amp;rsquo;t made it into the &lt;code&gt;pipeline&lt;/code&gt; yet. The queue is down to size three after a single message was removed. You also know that the &lt;code&gt;queue&lt;/code&gt; can hold ten messages, so the &lt;code&gt;producer&lt;/code&gt; thread didn&amp;rsquo;t get blocked by the &lt;code&gt;queue&lt;/code&gt;. It was swapped out by the OS.&lt;/p&gt;
&lt;div class=&quot;alert alert-primary&quot; role=&quot;alert&quot;&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Your output will be different. Your output will change from run to run. That&amp;rsquo;s the fun part of working with threads!&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;As the program starts to wrap up, can you see the main thread generating the &lt;code&gt;event&lt;/code&gt; which causes the &lt;code&gt;producer&lt;/code&gt; to exit immediately. The &lt;code&gt;consumer&lt;/code&gt; still has a bunch of work do to, so it keeps running until it has cleaned out the &lt;code&gt;pipeline&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Try playing with different queue sizes and calls to &lt;code&gt;time.sleep()&lt;/code&gt; in the &lt;code&gt;producer&lt;/code&gt; or the &lt;code&gt;consumer&lt;/code&gt; to simulate longer network or disk access times respectively. Even slight changes to these elements of the program will make large differences in your results.&lt;/p&gt;
&lt;p&gt;This is a much better solution to the producer-consumer problem, but you can simplify it even more. The &lt;code&gt;Pipeline&lt;/code&gt; really isn&amp;rsquo;t needed for this problem. Once you take away the logging, it just becomes a &lt;code&gt;queue.Queue&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s what the final code looks like using &lt;code&gt;queue.Queue&lt;/code&gt; directly:&lt;/p&gt;
&lt;div class=&quot;highlight python&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;concurrent.futures&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;logging&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;queue&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;random&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;threading&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;time&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;producer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;queue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;sd&quot;&gt;&amp;quot;&amp;quot;&amp;quot;Pretend we&amp;#39;re getting a number from the network.&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;is_set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;message&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;random&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;randint&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;101&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;logging&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;info&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;Producer got message: &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%s&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;queue&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;put&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;logging&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;info&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;Producer received event. Exiting&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;consumer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;queue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;sd&quot;&gt;&amp;quot;&amp;quot;&amp;quot;Pretend we&amp;#39;re saving a number in the database.&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;is_set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;queue&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;empty&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;message&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;queue&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;logging&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;info&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
            &lt;span class=&quot;s2&quot;&gt;&amp;quot;Consumer storing message: &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%s&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; (size=&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%d&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;)&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;queue&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;qsize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;logging&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;info&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;Consumer received event. Exiting&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;vm&quot;&gt;__name__&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;__main__&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;format&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%(asctime)s&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%(message)s&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;logging&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;basicConfig&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;format&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;format&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;level&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;logging&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;INFO&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                        &lt;span class=&quot;n&quot;&gt;datefmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;%H:%M:%S&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;pipeline&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;queue&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Queue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;maxsize&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;event&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;threading&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Event&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;concurrent&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;futures&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ThreadPoolExecutor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;max_workers&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;executor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;executor&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;submit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;producer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pipeline&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;executor&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;submit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;consumer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pipeline&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

        &lt;span class=&quot;n&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sleep&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;logging&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;info&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;Main: about to set event&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;That&amp;rsquo;s easier to read and shows how using Python&amp;rsquo;s built-in primitives can simplify a complex problem.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Lock&lt;/code&gt; and &lt;code&gt;Queue&lt;/code&gt; are handy classes to solve concurrency issues, but there are others provided by the standard library. Before you wrap up this tutorial, let&amp;rsquo;s do a quick survey of some of them.&lt;/p&gt;
&lt;h2 id=&quot;threading-objects&quot;&gt;Threading Objects&lt;/h2&gt;
&lt;p&gt;There are a few more primitives offered by the Python &lt;code&gt;threading&lt;/code&gt; module. While you didn&amp;rsquo;t need these for the examples above, they can come in handy in different use cases, so it&amp;rsquo;s good to be familiar with them.&lt;/p&gt;
&lt;h3 id=&quot;semaphore&quot;&gt;Semaphore&lt;/h3&gt;
&lt;p&gt;The first Python &lt;code&gt;threading&lt;/code&gt; object to look at is &lt;code&gt;threading.Semaphore&lt;/code&gt;. A &lt;code&gt;Semaphore&lt;/code&gt; is a counter with a few special properties. The first one is that the counting is atomic. This means that there is a guarantee that the operating system will not swap out the thread in the middle of incrementing or decrementing the counter.&lt;/p&gt;
&lt;p&gt;The internal counter is incremented when you call &lt;code&gt;.release()&lt;/code&gt; and decremented when you call &lt;code&gt;.acquire()&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The next special property is that if a thread calls &lt;code&gt;.acquire()&lt;/code&gt; when the counter is zero, that thread will block until a different thread calls &lt;code&gt;.release()&lt;/code&gt; and increments the counter to one.&lt;/p&gt;
&lt;p&gt;Semaphores are frequently used to protect a resource that has a limited capacity. An example would be if you have a pool of connections and want to limit the size of that pool to a specific number.&lt;/p&gt;
&lt;h3 id=&quot;timer&quot;&gt;Timer&lt;/h3&gt;
&lt;p&gt;A &lt;code&gt;threading.Timer&lt;/code&gt; is a way to schedule a function to be called after a certain amount of time has passed. You create a &lt;code&gt;Timer&lt;/code&gt; by passing in a number of seconds to wait and a function to call:&lt;/p&gt;
&lt;div class=&quot;highlight python&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;threading&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Timer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;30.0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;my_function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You start the &lt;code&gt;Timer&lt;/code&gt; by calling &lt;code&gt;.start()&lt;/code&gt;. The function will be called on a new thread at some point after the specified time, but be aware that there is no promise that it will be called exactly at the time you want.&lt;/p&gt;
&lt;p&gt;If you want to stop a &lt;code&gt;Timer&lt;/code&gt; that you&amp;rsquo;ve already started, you can cancel it by calling &lt;code&gt;.cancel()&lt;/code&gt;. Calling &lt;code&gt;.cancel()&lt;/code&gt; after the &lt;code&gt;Timer&lt;/code&gt; has triggered does nothing and does not produce an exception.&lt;/p&gt;
&lt;p&gt;A &lt;code&gt;Timer&lt;/code&gt; can be used to prompt a user for action after a specific amount of time. If the user does the action before the &lt;code&gt;Timer&lt;/code&gt; expires, &lt;code&gt;.cancel()&lt;/code&gt; can be called.&lt;/p&gt;
&lt;h3 id=&quot;barrier&quot;&gt;Barrier&lt;/h3&gt;
&lt;p&gt;A &lt;code&gt;threading.Barrier&lt;/code&gt; can be used to keep a fixed number of threads in sync. When creating a &lt;code&gt;Barrier&lt;/code&gt;, the caller must specify how many threads will be synchronizing on it. Each thread calls &lt;code&gt;.wait()&lt;/code&gt; on the &lt;code&gt;Barrier&lt;/code&gt;. They all will remain blocked until the specified number of threads are waiting, and then the are all released at the same time.&lt;/p&gt;
&lt;p&gt;Remember that threads are scheduled by the operating system so, even though all of the threads are released simultaneously, they will be scheduled to run one at a time.&lt;/p&gt;
&lt;p&gt;One use for a &lt;code&gt;Barrier&lt;/code&gt; is to allow a pool of threads to initialize themselves. Having the threads wait on a &lt;code&gt;Barrier&lt;/code&gt; after they are initialized will ensure that none of the threads start running before all of the threads are finished with their initialization.&lt;/p&gt;
&lt;h2 id=&quot;conclusion-threading-in-python&quot;&gt;Conclusion: Threading in Python&lt;/h2&gt;
&lt;p&gt;You&amp;rsquo;ve now seen much of what Python &lt;code&gt;threading&lt;/code&gt; has to offer and some examples of how to build threaded programs and the problems they solve. You&amp;rsquo;ve also seen a few instances of the problems that arise when writing and debugging threaded programs.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;d like to explore other options for concurrency in Python, check out &lt;a href=&quot;https://realpython.com/python-concurrency/&quot;&gt;Speed Up Your Python Program With Concurrency&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re interested in doing a deep dive on the &lt;code&gt;asyncio&lt;/code&gt; module, go read &lt;a href=&quot;https://realpython.com/async-io-python/&quot;&gt;Async IO in Python: A Complete Walkthrough&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Whatever you do, you now have the information and confidence you need to write programs using Python threading!&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Special thanks to reader JL Diaz for helping to clean up the introduction.&lt;/em&gt;&lt;/p&gt;
&lt;div class=&quot;alert alert-primary&quot; role=&quot;alert&quot;&gt;
&lt;p&gt;&lt;strong&gt;&lt;i class=&quot;fa fa-graduation-cap&quot; aria-hidden=&quot;true&quot;&gt;&lt;/i&gt; Take the Quiz:&lt;/strong&gt; Test your knowledge with our interactive “Python Threading” quiz. Upon completion you will receive a score so you can track your learning progress over time:&lt;/p&gt;&lt;p class=&quot;text-center my-2&quot;&gt;&lt;a class=&quot;btn btn-primary&quot; href=&quot;/quizzes/python-threading/&quot; target=&quot;_blank&quot;&gt;Take the Quiz »&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
        &lt;hr /&gt;
        &lt;p&gt;&lt;em&gt;[ Improve Your Python With 🐍 Python Tricks 💌 – Get a short &amp;amp; sweet Python Trick delivered to your inbox every couple of days. &lt;a href=&quot;https://realpython.com/python-tricks/?utm_source=realpython&amp;amp;utm_medium=rss&amp;amp;utm_campaign=footer&quot;&gt;&amp;gt;&amp;gt; Click here to learn more and see examples&lt;/a&gt; ]&lt;/em&gt;&lt;/p&gt;
      </content>
    </entry>
  
    <entry>
      <title>Intro to Object-Oriented Programming (OOP) in Python</title>
      <id>https://realpython.com/courses/intro-object-oriented-programming-oop-python/</id>
      <link href="https://realpython.com/courses/intro-object-oriented-programming-oop-python/"/>
      <updated>2019-03-21T14:00:00+00:00</updated>
      <summary>In this video series, you&#39;ll learn the fundamentals of object-oriented programming (OOP) in Python and how to work with classes, objects, and constructors.</summary>
      <content type="html">
        &lt;p&gt;Object-oriented programming is one of the biggest and most important subjects in all of programming. This series will provide you with a basic conceptual understanding of Object-Oriented Programming so you can take your Python programming skills to the next level.&lt;/p&gt;
&lt;p&gt;You&amp;rsquo;ll learn how to define custom types using classes, and how to instantiate those classes into python objects that can be used throughout your program.&lt;/p&gt;
&lt;p&gt;Finally, you&amp;rsquo;ll learn how classes can subclass one another with  brief introduction to inheritance, which allows you to write maintainable and less redundant Python code.&lt;/p&gt;
        &lt;hr /&gt;
        &lt;p&gt;&lt;em&gt;[ Improve Your Python With 🐍 Python Tricks 💌 – Get a short &amp;amp; sweet Python Trick delivered to your inbox every couple of days. &lt;a href=&quot;https://realpython.com/python-tricks/?utm_source=realpython&amp;amp;utm_medium=rss&amp;amp;utm_campaign=footer&quot;&gt;&amp;gt;&amp;gt; Click here to learn more and see examples&lt;/a&gt; ]&lt;/em&gt;&lt;/p&gt;
      </content>
    </entry>
  
    <entry>
      <title>13 Project Ideas for Intermediate Python Developers</title>
      <id>https://realpython.com/intermediate-python-project-ideas/</id>
      <link href="https://realpython.com/intermediate-python-project-ideas/"/>
      <updated>2019-03-20T14:00:00+00:00</updated>
      <summary>In this article, you&#39;ll learn how you can get started on 13 Python project ideas that are just right for intermediate Python developers. They&#39;ll challenge you enough to help you become a better Pythonista but will still be doable!</summary>
      <content type="html">
        &lt;p&gt;Learning the basics of Python is a wonderful experience. But the euphoria of just learning can be replaced by the hunger for hands-on projects. It&amp;rsquo;s normal to want to build projects, hence the need for project ideas.&lt;/p&gt;
&lt;p&gt;The problem though is that some projects are either too simple for an intermediate Python developer or too hard. This article will suggest projects you can work on as an intermediate Python developer. These project ideas will provide the appropriate level of challenge for you.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;In this article, you&amp;rsquo;ll learn:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The importance of building projects&lt;/li&gt;
&lt;li&gt;The major platforms you can build projects for&lt;/li&gt;
&lt;li&gt;Thirteen project ideas you can work on&lt;/li&gt;
&lt;li&gt;Some tips for working on projects&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;alert alert-warning&quot; role=&quot;alert&quot;&gt;&lt;p&gt;&lt;strong&gt;Free Bonus:&lt;/strong&gt; &lt;a href=&quot;&quot; class=&quot;alert-link&quot; data-toggle=&quot;modal&quot; data-target=&quot;#modal-python-mastery-course&quot; data-focus=&quot;false&quot;&gt;5 Thoughts On Python Mastery&lt;/a&gt;, a free course for Python developers that shows you the roadmap and the mindset you&#39;ll need to take your Python skills to the next level.&lt;/p&gt;&lt;/div&gt;

&lt;h2 id=&quot;the-importance-of-building-projects&quot;&gt;The Importance of Building Projects&lt;/h2&gt;
&lt;p&gt;Working on projects is vital to pushing your career as a Python developer forward. They make you apply the skills and knowledge you&amp;rsquo;re acquiring.&lt;/p&gt;
&lt;p&gt;Projects can help you:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Build confidence&lt;/strong&gt;: You will believe more in your ability to create software regardless the level of complexity.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Explore other technologies&lt;/strong&gt;: You will learn about other technologies needed in building a complete product such as databases, servers, and other languages.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Understand programming concepts better&lt;/strong&gt;: You will learn to write code better and understand concepts such as design patterns and object-oriented programming.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Experience a complete software development life cycle&lt;/strong&gt;: You will learn how to plan before writing code, manage the coding process and update software.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;There is a lot to gain from building projects as a Python developer.&lt;/p&gt;
&lt;h2 id=&quot;choosing-a-project-platform&quot;&gt;Choosing a Project Platform&lt;/h2&gt;
&lt;p&gt;You need to build your software to run on a platform so that people who lack certain technical knowledge can use your software. The web, desktop, and command-line are the three major platforms you&amp;rsquo;ll want to build your projects for.&lt;/p&gt;
&lt;h3 id=&quot;web&quot;&gt;Web&lt;/h3&gt;
&lt;p&gt;Web applications are applications that run on the web, they can be accessed on any device without being downloaded, provided there is access to the internet. If you want your projects to be accessible by everyone with internet access, it needs to be a web application. &lt;/p&gt;
&lt;p&gt;A web application has a back end and front end. The back end is the part where the business logic is: your back-end code will manipulate and store data. The front end is the interface of the application: your front-end code will determine the look of a web application.&lt;/p&gt;
&lt;p&gt;As an intermediate Python developer, your major focus will be the back-end code. However, the front-end code is important too, so you will need some knowledge of HTML, CSS, and maybe JavaScript to create a simple-looking interface. Just the basics will be enough.&lt;/p&gt;
&lt;p&gt;Another option is to use Python for both the front end and back end. Thanks to the &lt;a href=&quot;https://anvil.works/learn&quot;&gt;&lt;code&gt;anvil&lt;/code&gt;&lt;/a&gt; library, which eliminates the need for HTML, CSS, and JavaScript, you can focus on Python code alone.&lt;/p&gt;
&lt;p&gt;You can build web applications with Python through web frameworks such as &lt;a href=&quot;https://www.djangoproject.com/&quot;&gt;&lt;code&gt;django&lt;/code&gt;&lt;/a&gt; and &lt;a href=&quot;http://flask.pocoo.org/&quot;&gt;&lt;code&gt;flask&lt;/code&gt;&lt;/a&gt;. The list of frameworks for building web applications using Python is long. There are plenty to choose from, but &lt;code&gt;django&lt;/code&gt; and &lt;code&gt;flask&lt;/code&gt; remain the most popular web frameworks.&lt;/p&gt;
&lt;h3 id=&quot;desktop-gui&quot;&gt;Desktop GUI&lt;/h3&gt;
&lt;p&gt;Every time you perform a task on your PC, be it a desktop or laptop, it is through an application. As an intermediate Python developer, you can make your own desktop applications. &lt;/p&gt;
&lt;p&gt;You do not have to learn any front-end technology to create your own Graphical User Interface (GUI) applications, as you saw with web applications. You can build all the parts using Python.&lt;/p&gt;
&lt;p&gt;There are frameworks for building your desktop applications. &lt;a href=&quot;https://pysimplegui.readthedocs.io/tutorial/&quot;&gt;&lt;code&gt;PySimpleGUI&lt;/code&gt;&lt;/a&gt; is one of them, and it&amp;rsquo;s pretty user-friendly for an intermediate Python developer. &lt;/p&gt;
&lt;p&gt;An advanced GUI framework like &lt;a href=&quot;https://pypi.org/project/PyQt5/&quot;&gt;&lt;code&gt;PyQt5&lt;/code&gt;&lt;/a&gt; is quite powerful, but it may have a steep learning curve.&lt;/p&gt;
&lt;p&gt;The software you create for the Desktop GUI is able to work on any of the Windows, Linux, or Mac operating systems. All you have to do after creating the project is compile it to an executable for your operating system of choice.&lt;/p&gt;
&lt;h3 id=&quot;command-line&quot;&gt;Command-Line&lt;/h3&gt;
&lt;p&gt;Command-line applications are those applications that work in a console window. This is the command prompt on Windows and the Terminal on Linux and Mac. &lt;/p&gt;
&lt;p&gt;You&amp;rsquo;d click to use a web or GUI application, but you&amp;rsquo;d type in commands for command-line applications. Users of command-line applications need to have some technical knowledge since they&amp;rsquo;ll need to use commands.&lt;/p&gt;
&lt;p&gt;Command-line applications may not be as beautiful or easy to use as web or GUI applications, but that doesn&amp;rsquo;t make them less powerful than web or GUI applications.&lt;/p&gt;
&lt;p&gt;You can improve the look of your command-line applications by applying colors to the text. There are libraries you can use for coloring, such as &lt;a href=&quot;https://pypi.org/project/colorama/&quot;&gt;&lt;code&gt;colorama&lt;/code&gt;&lt;/a&gt; and &lt;a href=&quot;https://pypi.org/project/colored/&quot;&gt;&lt;code&gt;colored&lt;/code&gt;&lt;/a&gt;. You can spice things up and use some color.&lt;/p&gt;
&lt;p&gt;You can use frameworks such as &lt;a href=&quot;https://realpython.com/comparing-python-command-line-parsing-libraries-argparse-docopt-click/&quot;&gt;&lt;code&gt;docopt&lt;/code&gt;, &lt;code&gt;argparse&lt;/code&gt;, and &lt;code&gt;click&lt;/code&gt;&lt;/a&gt; to build your applications.&lt;/p&gt;
&lt;h2 id=&quot;web-project-ideas&quot;&gt;Web Project Ideas&lt;/h2&gt;
&lt;p&gt;In this section, you&amp;rsquo;ll see project ideas for the web. These project ideas can be classified as utility and education tools. &lt;/p&gt;
&lt;p&gt;Here are the project ideas:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Content Aggregator&lt;/li&gt;
&lt;li&gt;Regex Query Tool&lt;/li&gt;
&lt;li&gt;URL Shortener&lt;/li&gt;
&lt;li&gt;Post-It Note&lt;/li&gt;
&lt;li&gt;Quiz Application&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;content-aggregator&quot;&gt;Content Aggregator&lt;/h3&gt;
&lt;p&gt;Content is king. It exists everywhere on the web, from blogs to social media platforms. To keep up, you need to search for new information on the internet constantly. One way to stay updated is to check all the sites manually to see what the new posts are. But this is time consuming and quite tiring.&lt;/p&gt;
&lt;p&gt;This is where the content aggregator comes in: A content aggregator fetches information from various places online and gathers all of that information in one place. Therefore, you don&amp;rsquo;t have to visit multiple sites to get the latest info: one website is enough.&lt;/p&gt;
&lt;p&gt;With the content aggregator, all of the latest information can be gotten from one site that aggregates all the content. People can see the posts that interest them and can decide to find out more about them without traipsing all over the internet. &lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Examples of Content Aggregators&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Here are some implementations of the Content Aggregator idea:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://alltop.com/&quot;&gt;AllTop&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.hvper.com/&quot;&gt;Hvper&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Technical Details&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The main objective of this project idea is to aggregate content. First, you need to know what sites you&amp;rsquo;ll want the Content Aggregator to get content from. Then, you can use libraries such as &lt;a href=&quot;https://realpython.com/python-requests/&quot;&gt;&lt;code&gt;requests&lt;/code&gt;&lt;/a&gt; for sending HTTP requests and &lt;a href=&quot;https://www.crummy.com/software/BeautifulSoup/bs4/doc/&quot;&gt;&lt;code&gt;BeautifulSoup&lt;/code&gt;&lt;/a&gt; to parse and scrape the necessary content from the sites.&lt;/p&gt;
&lt;p&gt;Your application can implement its content aggregation as a background process. Libraries such as &lt;code&gt;celery&lt;/code&gt; or &lt;code&gt;apscheduler&lt;/code&gt; can help with that. You can try out &lt;code&gt;apscheduler&lt;/code&gt;. It&amp;rsquo;s great for small background processes.&lt;/p&gt;
&lt;p&gt;After scraping content from various sites, you&amp;rsquo;ll need to save it somewhere. So, you&amp;rsquo;ll use a database to save the scraped content.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Extra Challenge&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;For a tougher challenge, you can add more websites. This will help you &lt;a href=&quot;https://realpython.com/python-web-scraping-practical-introduction/&quot;&gt;learn how to study and extract information from websites&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;You can also have users subscribe to certain sites that you aggregate. Then, at the end of the day, the content aggregator will send the articles for that day to the email address of the user.&lt;/p&gt;
&lt;h3 id=&quot;regex-query-tool&quot;&gt;Regex Query Tool&lt;/h3&gt;
&lt;p&gt;You and I deal with text daily. This article, which is also text, has a structure. This makes it easier for you to understand. Sometimes, you need to find certain information in text, and using the regular search tool in text editors can be ineffective. &lt;/p&gt;
&lt;p&gt;This is where the Regex Query Tool comes in. A regex is a set of strings, so the regex query tool will check for the validity of the queries. When the regex matches patterns in the text, it tells the user and highlights the matched patterns. So, your Regex Query Tool will check the validity of the regex strings passed in by the user.&lt;/p&gt;
&lt;p&gt;With the Regex Query Tool, users can quickly check the validity of their regex strings on the web. This makes it easier for them, instead of having to check the strings with a text editor.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Examples of Regex Query Tools&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Here are some implementations of the Regex Query Tool idea:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.freeformatter.com/regex-tester.html&quot;&gt;FreeFormatter&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.regextester.com/&quot;&gt;RegexTester&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Technical Details&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The main objective of this type of project is to tell the user the validity of the inputted query strings. You can make it give a positive or negative response such as &lt;code&gt;Query String Is Valid&lt;/code&gt; and &lt;code&gt;Query String Is Invalid&lt;/code&gt;, implementing the positive response in green and the negative in red.&lt;/p&gt;
&lt;p&gt;You don&amp;rsquo;t have to implement the query tool from scratch. You can use Python&amp;rsquo;s standard &lt;code&gt;re&lt;/code&gt; library, which you can use to run the query strings on the inputted text. The &lt;code&gt;re&lt;/code&gt; library will return &lt;code&gt;None&lt;/code&gt; when the query string matches nothing, and it&amp;rsquo;ll return the matched strings when positive.&lt;/p&gt;
&lt;p&gt;Some users may not understand regex fully, so you can make a page to explain how regex works. You can make documentation that is interesting enough to keep the users excited about learning and understanding regex.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Extra Challenge&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Making a project that just returns the validity of the regex is fine. But you can also add a replacement feature. This means the application will check for the validity of the regex and also allow users to replace the matched strings with something else. So the tool is no longer a find tool but also a replace tool.&lt;/p&gt;
&lt;h3 id=&quot;url-shortener&quot;&gt;URL Shortener&lt;/h3&gt;
&lt;p&gt;URLs can be extremely long and not user-friendly. When people share links or even try to remember a URL, it&amp;rsquo;s difficult because most URLs are filled with more difficult characters and don&amp;rsquo;t form meaningful words.&lt;/p&gt;
&lt;p&gt;This is where the URL Shortener comes in. A URL Shortener reduces the characters or letters in a URL, making them easier to read and remember. A URL like &lt;code&gt;xyz.com/wwryb78&amp;amp;svnhkn%sghq?sfiyh&lt;/code&gt; can be shortened to &lt;code&gt;xyz.com/piojwr&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;With the URL Shortener, URLs become a joy to work with.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Examples of URL Shorteners&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Here are some implementations of the URL Shortener idea:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://bitly.com/&quot;&gt;Bitly&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.msht.us/&quot;&gt;MeShort&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Technical Details&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The main objective of this project idea is to shorten URLs. The main task the application will accomplish is to shorten URLs and then redirect users to the original URL when the shortened URL is visited.&lt;/p&gt;
&lt;p&gt;In the application, the users will input the original URL, and they will get the new, shortened URL as the result. To do this, you can use a combination of the &lt;code&gt;random&lt;/code&gt; and &lt;code&gt;string&lt;/code&gt; modules to generate the characters for the shortened URL.&lt;/p&gt;
&lt;p&gt;Since users will visit the shortened URL days, months, or even years after, you&amp;rsquo;ll need to save the original and shortened URLs in a database. When a request comes in, the application checks if the URL exists and redirects to the original, or else it redirects to a 404 page.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Extra Challenge&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Generating a shortened URL with random characters makes for a better URL than the long, random ones. But, you can make the result better for the users. You can add a feature to customize URLs, so the users can customize the generated URLs themselves. &lt;/p&gt;
&lt;p&gt;Without a doubt, a custom &lt;code&gt;xyz.com/mysite&lt;/code&gt; URL is better than a randomly generated &lt;code&gt;xyz.com/piojwr&lt;/code&gt; URL.&lt;/p&gt;
&lt;h3 id=&quot;post-it-note&quot;&gt;Post-It Note&lt;/h3&gt;
&lt;p&gt;It&amp;rsquo;s human to have many thoughts and ideas in a day, but it&amp;rsquo;s also human to forget. One way to work around forgetting things is to jot them down before they disappear into thin air. While some of forgotten thoughts and ideas may be trivial, some can be quite powerful.&lt;/p&gt;
&lt;p&gt;This is where a Post-It note comes in: A Post-It note is a small paper with low-tack adhesive at the back, making it attachable to surfaces such as documents, walls. Post-It notes make it easier to jot things down. The Post-It note project idea is something similar. It allows users to jot things down, making them accessible anywhere, since it&amp;rsquo;s a web application.&lt;/p&gt;
&lt;p&gt;With the Post-It note, people can now jot things down anywhere, without the fear of forgetting things or misplacing the notes&amp;mdash;which is a possibility with physical notes.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Examples of Post-It Notes&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Here are some implementations of the Post-It Note idea:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://pinup.com/&quot;&gt;Pinup&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://note.ly/&quot;&gt;Note.ly&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Technical Details&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The main objective of this project is to allow users to jot down thoughts. This means that each user will have their own notes, so the application will need to have an account creation feature. This ensures that the notes of each user remain private to them.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;django&lt;/code&gt; comes with a user authentication system, so it may be a good choice. You can use other frameworks like &lt;code&gt;bottle&lt;/code&gt; or &lt;code&gt;flask&lt;/code&gt;, but you&amp;rsquo;ll have to implement the user authentication system on your own.&lt;/p&gt;
&lt;p&gt;Since users may need to separate their notes under different sections, implementing a feature to allow users to categorize their notes will make the application more useful. &lt;/p&gt;
&lt;p&gt;As an example, you may need to have notes on algorithms and data structures, so you&amp;rsquo;ll need to be able to separate the notes in those categories.&lt;/p&gt;
&lt;p&gt;You&amp;rsquo;ll need to store the information and notes of each user, so a database becomes an essential part of this project. The &lt;code&gt;MySQLdb&lt;/code&gt; module can be used if you want to use a MySQL database or the &lt;code&gt;psycopg2&lt;/code&gt; module for a PostgreSQL database. There are other modules you can use, but it all depends on the database you choose to use.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Extra Challenge&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Since it&amp;rsquo;s human for users to forget their ideas, it&amp;rsquo;s also human for them to forget that they even made a note somewhere. You can add a feature to remind users of their notes. This feature will allow users to set a time for the reminder, so the application will send the reminder to the users when it&amp;rsquo;s time, by email.&lt;/p&gt;
&lt;h3 id=&quot;quiz-application&quot;&gt;Quiz Application&lt;/h3&gt;
&lt;p&gt;Knowledge is power. There are so many things in the world to learn, and quizzes help in testing the understanding of those concepts. You, as an intermediate Python developer, do not have to understand everything about the language. Taking tests is one way to find out things you don&amp;rsquo;t fully understand.&lt;/p&gt;
&lt;p&gt;This is where the Quiz Application comes in. The Quiz Application will present questions to the users and expect the right answers to those questions. Think of the Quiz Application as a kind of questionnaire. &lt;/p&gt;
&lt;p&gt;With the Quiz Application, special users you can call administrators will be allowed to create tests, so regular users can answer the questions and test their understanding of the topics in the quiz. &lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Examples of Quiz Applications&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Here are some implementations of the Quiz Application idea:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://myquiz.org/&quot;&gt;myQuiz&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://kahoot.com/&quot;&gt;Kahoot&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Technical Details&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The main objective of this project is to set quizzes and have people answer them. Therefore, users should be able to set questions, and other users should be able to answer those questions. The application will then display the final score and the right answers.&lt;/p&gt;
&lt;p&gt;If you want users to be able to have a record of their scores, you may have to implement an account creation feature. &lt;/p&gt;
&lt;p&gt;Users creating the tests should be able to create tests with the questions and answers by simply uploading a text file. The text file will have a format that you can decide, so the application can convert from a file to a quiz.&lt;/p&gt;
&lt;p&gt;You&amp;rsquo;ll need to implement a database for this project. The database will store the questions, possible answers, correct answers, and the scores for each user.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Extra Challenge&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;For more of a challenge, you can allow users to add timers to the quizzes. This way, the creators of a quiz can determine how many seconds or minutes a user should spend on each question in the quiz. &lt;/p&gt;
&lt;p&gt;It would be great to also have a quiz-sharing feature, so users can share interesting quizzes with their friends on other platforms.&lt;/p&gt;
&lt;h2 id=&quot;gui-project-ideas&quot;&gt;GUI Project Ideas&lt;/h2&gt;
&lt;p&gt;In this section, you&amp;rsquo;ll see project ideas for Graphical User Interfaces. These project ideas can be classified as entertainment, finance, and utility tools. &lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s are the project ideas:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;MP3 Player&lt;/li&gt;
&lt;li&gt;Alarm Tool&lt;/li&gt;
&lt;li&gt;File Manager&lt;/li&gt;
&lt;li&gt;Expense Tracker&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;mp3-player&quot;&gt;MP3 Player&lt;/h3&gt;
&lt;p&gt;Audio is as important as text today if not more important. Since audio files are digital files, you&amp;rsquo;ll need a tool that can play them. Without a player, you&amp;rsquo;ll never be able to listen to the contents of an audio file.&lt;/p&gt;
&lt;p&gt;This is where the MP3 Player comes in. The MP3 Player is a device for playing MP3s and other digital audio files. This MP3 Player GUI project idea attempts to emulate the physical MP3 Player. You can build software that allows you play an MP3 files on your desktop or laptop computer.&lt;/p&gt;
&lt;p&gt;When you are done building the MP3 Player project, users can play their MP3 files and other digital audio files without having to purchase a physical MP3 Player. They&amp;rsquo;ll be able to play the MP3 files using their computers.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Examples of MP3 Players&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Here are some implementations of the MP3 Player idea:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://getmusicbee.com/&quot;&gt;MusicBee&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.foobar2000.org/&quot;&gt;Foobar2000&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Technical Details&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The main objective of this project is to allow users to play MP3 and digital audio files. To be engaging for users, the application has to have a simple but beautiful user interface.&lt;/p&gt;
&lt;p&gt;You can have an interface for listing the available MP3 files. You can also give users the option to list other digital audio files that are not MP3.&lt;/p&gt;
&lt;p&gt;The users will also expect the MP3 Player to have an interface that shows information on the file that is playing. Some of the information you can include are the name of the file, its length, the amount played, and the amount not played, in minutes and seconds.&lt;/p&gt;
&lt;p&gt;Python has libraries that can play audio files, such as &lt;a href=&quot;https://pypi.org/project/Pygame/&quot;&gt;&lt;code&gt;pygame&lt;/code&gt;&lt;/a&gt;, which allows you to work with multimedia files in few lines of code. You can also check out &lt;a href=&quot;https://pypi.org/project/PyMedia/&quot;&gt;&lt;code&gt;pymedia&lt;/code&gt;&lt;/a&gt; and &lt;a href=&quot;https://pypi.org/project/simpleaudio/&quot;&gt;&lt;code&gt;simpleaudio&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;These libraries can handle a lot of digital audio files. They can handle other file types, not just the MP3 files.&lt;/p&gt;
&lt;p&gt;You can also implement a feature that allows users to create a playlist. To do this, you&amp;rsquo;ll need a database to store information on the created playlists. Python&amp;rsquo;s &lt;code&gt;sqlite3&lt;/code&gt; module allows you to use the SQLite database.&lt;/p&gt;
&lt;p&gt;The SQLite database is a better option in this case, because it is file based and easier to set up than other SQL databases. While SQLite is file based, &lt;a href=&quot;https://stackoverflow.com/questions/19946298/what-is-the-advantage-of-using-sqlite-rather-than-file&quot;&gt;it is better for saving data than a regular file&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Extra Challenge&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;For a more exciting challenge, you can add a feature to allow the MP3 player to repeat currently playing files or even shuffle the list of files to be played.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s also possible to implement a feature that allows users to increase and decrease the playing speed of the audio file. Users will find this interesting, as they&amp;rsquo;ll be able to play files at a slower or faster pace than usual.&lt;/p&gt;
&lt;h3 id=&quot;alarm-tool&quot;&gt;Alarm Tool&lt;/h3&gt;
&lt;p&gt;As they say, &amp;ldquo;Time and tide wait for no man.&amp;rdquo; But with a lot of things going on in our lives, it&amp;rsquo;s difficult to not lose track of time. To be able to keep track of time, a reminder is needed.&lt;/p&gt;
&lt;p&gt;This is where the Alarm Tool comes in. An alarm is a device that gives an audio or visual signal about a certain condition. This Alarm Tool project idea is an attempt to build an alarm as software. The Alarm Tool gives an audio signal when a certain condition is met. The set time is the certain condition in this case.&lt;/p&gt;
&lt;p&gt;With the Alarm Tool, users can set alarms to remind them of things at certain times of the day. The Alarm Tool project will work from the user&amp;rsquo;s laptop or desktop device, so they do not have to purchase a physical timer.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Examples of Alarm Tools&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Here are some implementations of the Alarm Tool idea:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://freealarmclocksoftware.com/&quot;&gt;FreeAlarmClock&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.apimac.com/mac/timer/&quot;&gt;TimerForMac&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Technical Details&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The main objective of this project is to activate audio signals at certain times of the day. So, timing and the audio signal to be played are the most important parts of the Alarm Tool.&lt;/p&gt;
&lt;p&gt;The Alarm Tool should allow users to create, edit, and delete alarms. It should also have an interface that lists all the alarms, provided they have not being deleted by the user. So, it should list the active and inactive alarms.&lt;/p&gt;
&lt;p&gt;Since it is an alarm, the application has to play tones at the set time. There are libraries for playing audio, like the &lt;a href=&quot;https://pypi.org/project/Pygame/&quot;&gt;&lt;code&gt;pygame&lt;/code&gt;&lt;/a&gt; library.&lt;/p&gt;
&lt;p&gt;In your code logic, the application has to keep checking for set alarm times. When the time is reached, it triggers a function to play the alarm tone.&lt;/p&gt;
&lt;p&gt;Since the application will check for set alarm times, it means the application has to save the alarms in a database. The database should store things like the alarm date, time, and tone location.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Extra Challenge&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;As an extra feature, you can allow users to set recurring alarms. They&amp;rsquo;ll be able to set alarms that will ring at a certain time on certain days of the week, every week. As an example, an alarm can be set at 2:00 PM every Monday.&lt;/p&gt;
&lt;p&gt;You can also add a snooze feature, so your users can snooze alarms instead of only dismissing them.&lt;/p&gt;
&lt;h3 id=&quot;file-manager&quot;&gt;File Manager&lt;/h3&gt;
&lt;p&gt;The number of files on the personal computer of an average PC user is pretty high. If all of those files were placed in a single directory, it would be difficult to navigate and find files or directories. So, there is a need to arrange the files and manage them properly.&lt;/p&gt;
&lt;p&gt;This is where a file manager comes in. A file manager allows users to manage files and directories through a user interface. While files can be managed through the command-line, not all users know how to do that.&lt;/p&gt;
&lt;p&gt;With a file manager, users can arrange, access, and administer their files and directories properly without knowing how to use the command line. Some of the tasks a file manager allows users to perform includes copying, moving, and renaming files or directories.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Examples of File Manager Tools&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Here are some implementations of the File Manager idea:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://freecommander.com/en/summary/&quot;&gt;FreeCommander&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://explorerplusplus.com/&quot;&gt;Explorer++&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Technical Details&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The main objective of the file manager project is to give users an interface to manage their files. Users want a file manager that has a file management tool that looks good and is easy to use. &lt;/p&gt;
&lt;p&gt;You can use the &lt;code&gt;PySimpleGUI&lt;/code&gt; library to create unique user interfaces with a powerful widget, without having to deal with a lot of complexity.&lt;/p&gt;
&lt;p&gt;Your users should be able to perform simple tasks like creating new directories or empty text files. They should also be able to copy and move files or directories. &lt;/p&gt;
&lt;p&gt;The &lt;code&gt;sys&lt;/code&gt;, &lt;code&gt;os&lt;/code&gt;, and &lt;code&gt;shutil&lt;/code&gt; libraries will be quite useful for this project, as they can be used to execute actions on the files in the background, while the user clicks away.&lt;/p&gt;
&lt;p&gt;The grid and list views are popular views today, so you can implement both in the application. This gives the user the option to choose which view option is suitable for them.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Extra Challenge&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;To make the file manager a bit more advanced, you can implement a search feature. So users can search for files and directories without having to find them manually.&lt;/p&gt;
&lt;p&gt;You can also implement a sort feature. This will allow users to sort files according to different orders, such as time, alphabetical order, or size.&lt;/p&gt;
&lt;h3 id=&quot;expense-tracker&quot;&gt;Expense Tracker&lt;/h3&gt;
&lt;p&gt;We have daily expenses, from groceries to clothing to bills. There are so many expenses that it&amp;rsquo;s normal to lose track of them and keep spending till we&amp;rsquo;re almost out of cash. A tracker can help people watch their expenses.&lt;/p&gt;
&lt;p&gt;This is where the expense tracker comes in. An expense tracker is a software tool that allows users to keep track of their expenses. It can also analyze the expenses, depending on how advanced it is, but let&amp;rsquo;s keep it simple for now.&lt;/p&gt;
&lt;p&gt;With the expense tracker, users can set a budget and track their spending so as to make better financial decisions.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Examples of Expense Trackers&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Here are some implementations of the Expense Tracker idea:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://buddi.digitalcave.ca/&quot;&gt;Buddi&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.gnucash.org/&quot;&gt;GnuCash&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Technical Details&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The main objective of this project is to keep track of the user&amp;rsquo;s expenses. Some statistical analysis has to be done to be able to give users correct information on their expenses and help them spend better.&lt;/p&gt;
&lt;p&gt;While tracking the expenses is the key thing, a good interface is also important. With &lt;code&gt;PySimpleGUI&lt;/code&gt;, you can create a unique interface to improve the experience of the users.&lt;/p&gt;
&lt;p&gt;PyData libraries such as &lt;code&gt;pandas&lt;/code&gt; and &lt;code&gt;matplotlib&lt;/code&gt; can be helpful for building the expense tracker. &lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;https://pandas.pydata.org/pandas-docs/stable/&quot;&gt;&lt;code&gt;pandas&lt;/code&gt;&lt;/a&gt; library can be used for the data analysis, and the &lt;a href=&quot;https://matplotlib.org/&quot;&gt;&lt;code&gt;matplotlib&lt;/code&gt;&lt;/a&gt; library can be used for plotting graphs. Graphs will give the users a visual representation of their expenses, and a visual representation is usually easier to understand.&lt;/p&gt;
&lt;p&gt;The application will receive data from the users. The data here is the inputted expenses. So, you&amp;rsquo;ll have to store the expenses in a database. The SQLite database is a good database choice for this project since it can be set up quickly. You can use &lt;code&gt;sqlite3&lt;/code&gt; module for the SQLite database.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Extra Challenge&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;For your users to benefit from this project, they&amp;rsquo;ll have to input their expenses regularly, which might slip their mind. 
It could be useful for you to implement a reminder feature. So the application will send a notification at certain times of the day or the week, reminding them to make use of the expense tracker.&lt;/p&gt;
&lt;h2 id=&quot;command-line-project-ideas&quot;&gt;Command-Line Project Ideas&lt;/h2&gt;
&lt;p&gt;In this section, you&amp;rsquo;ll see project ideas for the command-line. The project ideas discussed can be classified as utility tools. &lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s are the project ideas:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Contact Book&lt;/li&gt;
&lt;li&gt;File Connectivity Checker&lt;/li&gt;
&lt;li&gt;Bulk File Rename Tool&lt;/li&gt;
&lt;li&gt;Directory Tree Generator&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;contact-book&quot;&gt;Contact Book&lt;/h3&gt;
&lt;p&gt;We come across lots of people daily. We make acquaintances and friends. We get their contacts to keep in touch later on. Sadly, keeping the received contact details can be hard. One way to do this is to write the contact details down. But this is not secure as the physical book can easily be lost.&lt;/p&gt;
&lt;p&gt;This is where the Contact Book project comes in. A contact book is a tool for saving a contact&amp;rsquo;s details, such as name, address, phone number, and email address. With this contact book project, you can build a software tool that people can use to save and find contact details.&lt;/p&gt;
&lt;p&gt;With the contact book project idea, users can save their contacts with less risk of losing the saved contact details. It&amp;rsquo;ll always be accessible from their computer, through the command-line.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Examples of Contact Book Tools&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;There are Contact Book applications, but it&amp;rsquo;s rare to find command-line Contact Book products, as most are web, mobile, or GUI applications.&lt;/p&gt;
&lt;p&gt;Here are some implementations of the Contact Book idea:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://play.google.com/store/apps/details?id=com.simplemobiletools.contacts&amp;amp;hl=en_US&quot;&gt;Simple Contacts&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://connect.pobuca.com/&quot;&gt;Pobuca Connect&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Technical Details&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The main objective of this project is to save contact details. It&amp;rsquo;s important that you set up the commands users can use to enter the contact details. You can use the &lt;code&gt;argparse&lt;/code&gt; or &lt;code&gt;click&lt;/code&gt; command-line frameworks. They abstract a lot of complex stuff, so you only have to focus on the logic to be run when executing commands.&lt;/p&gt;
&lt;p&gt;Some features you should implement include the commands to delete contacts, update contact information, and list saved contacts. You can also allow users to list contacts using different parameters, such as alphabetical order or contact creation date.&lt;/p&gt;
&lt;p&gt;Since it&amp;rsquo;s a command-line project, the SQLite database will be fine for saving contacts. SQLite is user-friendly to set up. You may save the contact details in a file, but a file will not offer the benefits you can gain from using SQLite, such as performance and security.&lt;/p&gt;
&lt;p&gt;To use the SQLite database in this project, the Python &lt;code&gt;sqlite3&lt;/code&gt; module will be very useful.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Extra Challenge&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Remember how the database is stored on the user&amp;rsquo;s computer? What if something happens, like the user losing their files? It means they&amp;rsquo;ll also lose the contact details.&lt;/p&gt;
&lt;p&gt;You can challenge yourself further and backup the database to an online storage platform. To do this, you can upload the database files to the cloud at certain intervals.&lt;/p&gt;
&lt;p&gt;You can also add a command that allows users to backup the database themselves. This way, the user can still have access to the contacts if the database file is lost. &lt;/p&gt;
&lt;p&gt;You should note that you may need some form of identification, so the contact book can tell which database file belongs to which user. Implementing a user authentication feature is one way to go about it.&lt;/p&gt;
&lt;h3 id=&quot;site-connectivity-checker&quot;&gt;Site Connectivity Checker&lt;/h3&gt;
&lt;p&gt;When you visit a URL, you expect to get the requested pages on your browser. But this is not always the case. Sometimes, sites can be down, so you won&amp;rsquo;t get the desired results. Instead, you&amp;rsquo;ll be presented with error messages. You can keep trying a site that is down, till it comes up and you get the information you need.&lt;/p&gt;
&lt;p&gt;This is where the Site Connectivity Checker project comes in. The Site Connectivity Checker visits a URL and returns the status of the URL: it is either live or not. The Site Connectivity Checker will visit the URL at intervals, returning the results of each visit.&lt;/p&gt;
&lt;p&gt;Instead of manually visiting a URL, a Site Connectivity Checker can do all of that manual work for you. This way, you&amp;rsquo;ll only get the results of the check without having to spend time on the browser, waiting for the site to go live.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Examples of Site Connectivity Checkers&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Here are some implementations of the Site Connectivity Checker idea:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Ping_(networking_utility)&quot;&gt;Ping&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.site24x7.com/check-website-availability.html&quot;&gt;Site24x7&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Technical Details&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The main objective of this project is to check the status of sites. So, you need to write code for checking the status of a website.&lt;/p&gt;
&lt;p&gt;You can choose to use either &lt;a href=&quot;https://en.wikipedia.org/wiki/Transmission_Control_Protocol&quot;&gt;TCP&lt;/a&gt; or &lt;a href=&quot;https://en.wikipedia.org/wiki/Internet_Control_Message_Protocol&quot;&gt;ICMP&lt;/a&gt; for your connections. The &lt;a href=&quot;https://docs.python.org/3/library/socket.html&quot;&gt;&lt;code&gt;socket&lt;/code&gt;&lt;/a&gt; module is one to check out. You can also read &lt;a href=&quot;https://realpython.com/python-sockets/&quot;&gt;Socket Programming in Python (Guide)&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Through your chosen framework, be it the &lt;code&gt;docopt&lt;/code&gt;, &lt;code&gt;click&lt;/code&gt;, or &lt;code&gt;argparse&lt;/code&gt; framework, you can add commands to allow users to add and remove sites from the list of sites to be checked.&lt;/p&gt;
&lt;p&gt;The users should also be able to start the tool, stop it, and determine the intervals.&lt;/p&gt;
&lt;p&gt;Since you&amp;rsquo;ll have to save the list of files to be checked, you can either save it in a file (just a list of sites) or use a SQLite database through the &lt;code&gt;sqlite3&lt;/code&gt; module.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Extra Challenge&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The application can check for the connectivity status of sites and display the results to the command-line. But this will require the user to keep checking the command-line. &lt;/p&gt;
&lt;p&gt;You can increase the challenge and implement a notification feature. The notification feature can be a sound played in the background to alert the user when a site&amp;rsquo;s status changes. You&amp;rsquo;ll need a database to store the previous status of a site. That&amp;rsquo;s the only way the tool can tell when the status changes.&lt;/p&gt;
&lt;h3 id=&quot;bulk-file-rename-tool&quot;&gt;Bulk File Rename Tool&lt;/h3&gt;
&lt;p&gt;Sometimes, you need to name all the files in a directory according to certain conventions. For example, you can name all the files in a directory with &lt;code&gt;File0001.jpg&lt;/code&gt;, where the numbers increase based on the number of files in the directory. Doing this manually can be stressful and repetitive.&lt;/p&gt;
&lt;p&gt;The Bulk File Rename Tool allows users to rename a large number of files, without having to manually rename files.&lt;/p&gt;
&lt;p&gt;This saves users a lot of time. It spares them the trouble of having to do boring repetitive work and make mistakes. With the Bulk File Rename Tool, users can rename files in a couple of seconds without any mistakes.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Examples of Bulk File Rename Tools&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Here are some implementations of the Bulk File Rename idea:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Ren_(command)&quot;&gt;Ren&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.tecmint.com/rename-multiple-files-in-linux/&quot;&gt;Rename&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Technical Details&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The main objective of this project idea is to rename files. So, the application needs to find a way to manipulate the target files. The &lt;code&gt;os&lt;/code&gt;, &lt;code&gt;sys&lt;/code&gt;, and &lt;code&gt;shutil&lt;/code&gt; libraries will be useful for a large part of this project.&lt;/p&gt;
&lt;p&gt;Your users will be able to rename all the files in the directory, using naming conventions. Therefore, they should be able to pass in the naming convention of choice. The &lt;code&gt;regex&lt;/code&gt; module will help match the required naming patterns, if you understand how regex works.&lt;/p&gt;
&lt;p&gt;A user may want to pass in a naming convention such as &lt;code&gt;myfiles&lt;/code&gt; as part of the commands and expect that the tool renames all the files like &lt;code&gt;myfilesXYZ&lt;/code&gt;, where &lt;code&gt;XYZ&lt;/code&gt; is a number. They should also be able to choose the directory where the files to be renamed are.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Extra Challenge&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The major challenge in this project is to rename all the files in a directory. But users may only need to name a certain number of files. To test your skills, you can implement a feature to allow users to choose the number of files to be renamed, instead of all the files. &lt;/p&gt;
&lt;p&gt;Note that renaming only a certain number of files will require the tool to sort the files based on alphabetical order, time of file creation, or file size, depending on the user&amp;rsquo;s requirements. &lt;/p&gt;
&lt;h3 id=&quot;directory-tree-generator&quot;&gt;Directory Tree Generator&lt;/h3&gt;
&lt;p&gt;Directories are like family trees: each directory has a particular relationship with other directories. No directories ever stays on its own, except an empty root directory. &lt;/p&gt;
&lt;p&gt;When you&amp;rsquo;re working with files and directories, it is difficult to see the relationship between directories, as you can only see what exists in the current directory. You&amp;rsquo;re either using a file manager or working from the command-line. &lt;/p&gt;
&lt;p&gt;With a Directory Tree Generator, you can see the relationship between files and directories like a tree or a map. &lt;/p&gt;
&lt;p&gt;This makes it easier to understand the positioning of files and directories. A directory tree map is important when you&amp;rsquo;re explaining certain concepts, and a Directory Tree Generator makes it easier to get a visual representation of the file and directory relationships.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Examples of Directory Tree Generators&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Here are some implementations of the Directory Tree Generator idea:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Tree_(command)&quot;&gt;Tree&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/mauriziodimatteo/dirtreex&quot;&gt;Dirtreex&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Technical Details&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The main objective of the Directory Tree Generator is to visualize the relationships between files and directories. The &lt;code&gt;os&lt;/code&gt; library can be very useful in listing the files and directories in a chosen directory.&lt;/p&gt;
&lt;p&gt;Using a framework such as &lt;code&gt;docopt&lt;/code&gt; or &lt;code&gt;argparse&lt;/code&gt; helps abstract a lot of stuff, allowing you to focus on writing code for the application&amp;rsquo;s logic.&lt;/p&gt;
&lt;p&gt;In the application&amp;rsquo;s logic, you can decide how you want to represent files or directories. Using different colors is a brilliant way to go about it. You can use the &lt;code&gt;colored&lt;/code&gt; library to print the files and directories in different colors. &lt;/p&gt;
&lt;p&gt;You can also decide how deep you&amp;rsquo;d like the Directory Tree Generator to go. For example, if a directory has children directories twelve levels deep, you may decide to go only as deep as the fifth level.&lt;/p&gt;
&lt;p&gt;If you wish, you can also let the user decide how deep they want the Directory Tree Generator to go.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Extra Challenge&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Since the results of the generated directory tree will be on the command-line, you can go one step further. You can have the generator create images of the directory tree, so it&amp;rsquo;ll basically turn the text into an image. &lt;/p&gt;
&lt;p&gt;You&amp;rsquo;ll find the &lt;a href=&quot;https://pillow.readthedocs.io/en/stable/&quot;&gt;&lt;code&gt;pillow&lt;/code&gt;&lt;/a&gt; library useful for doing this.&lt;/p&gt;
&lt;h2 id=&quot;tips-for-working-on-projects&quot;&gt;Tips for Working on Projects&lt;/h2&gt;
&lt;p&gt;Working on projects can be difficult. That&amp;rsquo;s one reason why motivation and interest in a project will make it a less daunting task.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re interested in a project, you&amp;rsquo;ll be able to put in the time to research as well as find libraries and tools that will help you with the project.&lt;/p&gt;
&lt;p&gt;Here are some tips:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Find a source of motivation&lt;/li&gt;
&lt;li&gt;Break the project into subtasks&lt;/li&gt;
&lt;li&gt;Do research on the subtasks&lt;/li&gt;
&lt;li&gt;Build each subtasks, one step at a time&lt;/li&gt;
&lt;li&gt;Reach out for help if you&amp;rsquo;re stuck&lt;/li&gt;
&lt;li&gt;Put the subtasks together&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;In this article, you&amp;rsquo;ve seen a couple of Python project ideas you may find interesting. &lt;/p&gt;
&lt;p&gt;The project ideas cover a range of platforms. You saw project ideas for the Web, GUI, and Command-line platforms. &lt;/p&gt;
&lt;p&gt;You can choose to build a project for different platforms. Using the URL Shortener as an example, you may choose to build one for the Web, GUI, or the Command-line.&lt;/p&gt;
&lt;p&gt;Since you&amp;rsquo;re an intermediate Python developer, these projects can be quite challenging but interesting.&lt;/p&gt;
&lt;p&gt;The best way to make a project happen is to just get started. In no time, you&amp;rsquo;ll be finished and discover how much you&amp;rsquo;ve benefited from working on a project!&lt;/p&gt;
        &lt;hr /&gt;
        &lt;p&gt;&lt;em&gt;[ Improve Your Python With 🐍 Python Tricks 💌 – Get a short &amp;amp; sweet Python Trick delivered to your inbox every couple of days. &lt;a href=&quot;https://realpython.com/python-tricks/?utm_source=realpython&amp;amp;utm_medium=rss&amp;amp;utm_campaign=footer&quot;&gt;&amp;gt;&amp;gt; Click here to learn more and see examples&lt;/a&gt; ]&lt;/em&gt;&lt;/p&gt;
      </content>
    </entry>
  

</feed>
