<?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-07-17T14:00:00+00:00</updated>
  <id>https://realpython.com/</id>
  <author>
    <name>Real Python</name>
  </author>

  
    <entry>
      <title>Create a Flask Application With Google Login</title>
      <id>https://realpython.com/flask-google-login/</id>
      <link href="https://realpython.com/flask-google-login/"/>
      <updated>2019-07-17T14:00:00+00:00</updated>
      <summary>In this step-by-step tutorial, you&#39;ll create a Flask application that lets users sign in using their Google login. You&#39;ll learn about OAuth 2 and OpenID Connect and also find out how to implement some code to handle user session management.</summary>
      <content type="html">
        &lt;p&gt;You&amp;rsquo;ve probably seen the option for &lt;em&gt;Google Login&lt;/em&gt; on various websites. Some sites also have more options like &lt;em&gt;Facebook Login&lt;/em&gt; or &lt;em&gt;GitHub Login&lt;/em&gt;. All these options allow users to utilize existing accounts to use a new service.&lt;/p&gt;
&lt;p&gt;In this article, you&amp;rsquo;ll work through the creation of a &lt;a href=&quot;https://realpython.com/tutorials/flask/&quot;&gt;Flask&lt;/a&gt; web application. Your application will allow a user to log in using their Google identity instead of creating a new account. There are tons of benefits with this method of user management. It&amp;rsquo;s going to be safer and simpler than managing the traditional username and password combinations.&lt;/p&gt;
&lt;p&gt;This article will be more straightforward if you already understand the &lt;a href=&quot;https://realpython.com/learning-paths/python3-introduction/&quot;&gt;basics of Python&lt;/a&gt;. It would also help to know a bit about web frameworks and HTTP requests, but that&amp;rsquo;s not strictly necessary.&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;Create a Flask web application that lets users log in with Google&lt;/li&gt;
&lt;li&gt;Create client credentials to interact with Google&lt;/li&gt;
&lt;li&gt;Use Flask-Login for user session management in a Flask application&lt;/li&gt;
&lt;li&gt;Better understand OAuth 2 and OpenID Connect (OIDC)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You can click the box below to get the code for the application you&amp;rsquo;ll make in this article:&lt;/p&gt;
&lt;div class=&quot;alert alert-warning&quot; role=&quot;alert&quot;&gt;&lt;p&gt;&lt;strong&gt;Download Sample Project:&lt;/strong&gt; &lt;a href=&quot;https://realpython.com/optins/view/google-login-project/&quot; class=&quot;alert-link&quot; data-toggle=&quot;modal&quot; data-target=&quot;#modal-google-login-project&quot; data-focus=&quot;false&quot;&gt;Click here to download the code for the Flask application with Google login you&#39;ll build in this article.&lt;/a&gt;&lt;/p&gt;&lt;/div&gt;

&lt;h2 id=&quot;why-use-google-login-for-your-users&quot;&gt;Why Use Google Login for Your Users?&lt;/h2&gt;
&lt;p&gt;You may want individual users to have profiles. Or perhaps you want to provide features to only certain users. In any case, you&amp;rsquo;ll need to know who&amp;rsquo;s interacting with your application. In other words, you&amp;rsquo;ll need to authenticate users and identify them in some unique way.&lt;/p&gt;
&lt;p&gt;The traditional solution is to use a unique username and a secret password. Your application would store that information and ask for it when needed. However, there are a few downsides to that solution:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You have to securely manage the passwords.&lt;/li&gt;
&lt;li&gt;You have to implement any account-related functionality:&lt;ul&gt;
&lt;li&gt;Two-factor authentication&lt;/li&gt;
&lt;li&gt;Password reset&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;You have to protect against malicious login attempts.&lt;/li&gt;
&lt;li&gt;Your users have to remember yet another username and password.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;By using Google login for your users, you push all that responsibility to them. Your application waits for the user to go through authentication. Google then tells your application about that user. At that point, you can effectively log them into your application.&lt;/p&gt;
&lt;p&gt;You don&amp;rsquo;t have to store any passwords, and Google handles all the security.&lt;/p&gt;
&lt;h2 id=&quot;how-applications-use-google-login&quot;&gt;How Applications Use Google Login&lt;/h2&gt;
&lt;p&gt;There are two very popular and important specifications called &lt;a href=&quot;https://tools.ietf.org/html/rfc6749&quot;&gt;OAuth 2&lt;/a&gt; and &lt;a href=&quot;https://openid.net/specs/openid-connect-core-1_0.html&quot;&gt;OpenID Connect (OIDC)&lt;/a&gt;. OIDC is built on top of OAuth 2, adding a few new ideas and concepts.&lt;/p&gt;
&lt;p&gt;These specifications define how a third-party application can obtain information from another service. This usually involves obtaining consent from a user. To unpack this a bit, let&amp;rsquo;s look at how this applies to the application you&amp;rsquo;re about to build.&lt;/p&gt;
&lt;p&gt;You&amp;rsquo;re about to write a third-party application, and it will let a user use a &lt;em&gt;Google Login&lt;/em&gt; button to log in. To do that, Google needs to know about your application. Luckily, you can register your application as a client to Google.&lt;/p&gt;
&lt;p&gt;Once a user comes to your application and presses the &lt;em&gt;Google Login&lt;/em&gt; button, you can send them to Google. From there, Google needs to make sure that the user consents to pass along their email and other information to your application. Should the user consent, Google sends back some information to your application. You then store that information and can reference it later, effectively logging the user in.&lt;/p&gt;
&lt;h2 id=&quot;openid-connect-details&quot;&gt;OpenID Connect Details&lt;/h2&gt;
&lt;p&gt;To request information on behalf of a user, you must become a &lt;code&gt;client&lt;/code&gt; to the authentication server, also known as the provider. The first thing you&amp;rsquo;ll realize if you dig into these specifications is that there are a lot of overlapping terms and concepts.&lt;/p&gt;
&lt;p&gt;So as a third-party application (also known as a client), you want to get info from the provider on the user&amp;rsquo;s behalf. There are a series of steps that enable that to happen, and those steps must happen in a specific order. That&amp;rsquo;s why you&amp;rsquo;ll sometimes hear OAuth 2 and OpenID Connect referred to as a &lt;strong&gt;handshake&lt;/strong&gt;, &lt;strong&gt;flow&lt;/strong&gt;, or &lt;strong&gt;dance&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Those steps are, broadly:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;You register a third-party application as a client to the provider:&lt;ul&gt;
&lt;li&gt;You receive unique client credentials from the provider.&lt;/li&gt;
&lt;li&gt;You&amp;rsquo;ll use these client credentials to authenticate (prove who you are) to the provider later on.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;The client sends a request to the provider&amp;rsquo;s &lt;code&gt;authorization&lt;/code&gt; URL&lt;/li&gt;
&lt;li&gt;The provider asks the user to authenticate (prove who they are)&lt;/li&gt;
&lt;li&gt;The provider asks the user to consent to the client acting on their behalf:&lt;ul&gt;
&lt;li&gt;Usually this includes limited access, and it&amp;rsquo;s made clear to the user what the client is asking for.&lt;/li&gt;
&lt;li&gt;This is like when you have to approve an app on your phone to have access to location or contacts.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;The provider sends the client a unique authorization code.&lt;/li&gt;
&lt;li&gt;The client sends the authorization code back to the Provider&amp;rsquo;s &lt;code&gt;token&lt;/code&gt; URL.&lt;/li&gt;
&lt;li&gt;The provider sends the client tokens to use with other provider URLs on behalf of the user.&lt;/li&gt;
&lt;/ol&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 steps above are for the Authorization Code Flow, as defined by OAuth 2.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;Those steps include both of the standards mentioned so far. OpenID Connect (OIDC) is built on top of OAuth 2, adding a few additional features and requirements, mostly involving the process of authentication. Other than the authentication mentioned in the flow above, the important OIDC concepts for your application are the &lt;strong&gt;provider configuration&lt;/strong&gt; and &lt;strong&gt;userinfo endpoint&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;provider configuration&lt;/strong&gt; contains information about the provider, including the exact URLs you need to use for the OAuth 2 flow. There&amp;rsquo;s a standard URL on an OIDC provider you can use to get back a document with &lt;a href=&quot;https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderMetadata&quot;&gt;standardized fields&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;&lt;a href=&quot;https://openid.net/specs/openid-connect-core-1_0.html#UserInfo&quot;&gt;userinfo endpoint&lt;/a&gt;&lt;/strong&gt; will return information about the user after you&amp;rsquo;ve gone through the OAuth 2 flow. This will include their email and some basic profile information you&amp;rsquo;ll use in your application. In order to obtain this user information, you&amp;rsquo;ll need a token from the provider, as described in the last step in the flow above.&lt;/p&gt;
&lt;p&gt;You&amp;rsquo;ll see the details about how the provider configuration and user info endpoint can be utilized later on.&lt;/p&gt;
&lt;h2 id=&quot;creating-a-google-client&quot;&gt;Creating a Google Client&lt;/h2&gt;
&lt;p&gt;The first step to enable a &lt;em&gt;Google Login&lt;/em&gt; option is to register your application as a client to Google. Let&amp;rsquo;s walk through the steps to do that.&lt;/p&gt;
&lt;p&gt;First, note that you will need a Google Account. You already have one if you use Gmail.&lt;/p&gt;
&lt;p&gt;Next, go to the &lt;a href=&quot;https://console.developers.google.com/apis/credentials&quot;&gt;Google developers credentials page&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Once in, you may be prompted to agree to their terms of service. Should you agree to those, press the &lt;em&gt;Create credentials&lt;/em&gt; button on the next page. Select the option for &lt;strong&gt;OAuth client ID&lt;/strong&gt;:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://files.realpython.com/media/client_id.8c970f445c4f.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/client_id.8c970f445c4f.png&quot; width=&quot;1194&quot; height=&quot;580&quot; srcset=&quot;https://robocrop.realpython.net/?url=https%3A//files.realpython.com/media/client_id.8c970f445c4f.png&amp;amp;w=298&amp;amp;sig=4f3172fd2531f877e271da274157a12952863571 298w, https://robocrop.realpython.net/?url=https%3A//files.realpython.com/media/client_id.8c970f445c4f.png&amp;amp;w=597&amp;amp;sig=b3b008238078cdbac910696845e49df0c95b8710 597w, https://files.realpython.com/media/client_id.8c970f445c4f.png 1194w&quot; sizes=&quot;75vw&quot; alt=&quot;Google create credentials screen shot&quot;/&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Select the &lt;code&gt;Web application&lt;/code&gt; option at the top. You can provide a name for the client in the &lt;code&gt;Name&lt;/code&gt; field as well. The name you provide will be displayed to users when they are consenting to your application acting on their behalf.&lt;/p&gt;
&lt;p&gt;You&amp;rsquo;ll be running your web application locally for now, so you can set the &lt;code&gt;Authorized JavaScript origins&lt;/code&gt; to &lt;code&gt;https://127.0.0.1:5000&lt;/code&gt; and &lt;code&gt;Authorized redirect URIs&lt;/code&gt; to &lt;code&gt;https://127.0.0.1:5000/login/callback&lt;/code&gt;. This will allow your local Flask application to communicate with Google.&lt;/p&gt;
&lt;p&gt;Finally, hit &lt;code&gt;Create&lt;/code&gt; and take note of the &lt;code&gt;client ID&lt;/code&gt; and &lt;code&gt;client secret&lt;/code&gt;. You&amp;rsquo;ll need both later.&lt;/p&gt;
&lt;h2 id=&quot;creating-your-own-web-application&quot;&gt;Creating Your Own Web Application&lt;/h2&gt;
&lt;p&gt;Now for the fun part where you apply the knowledge you learned to create an actual web application! &lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s start with the goal in mind. You want to create an application that lets users log in with their Google account. That application should be able to retrieve some basic information about the user from Google, like their email address. Then the application should store basic user information in a database.&lt;/p&gt;
&lt;p&gt;First, though, let&amp;rsquo;s take a look at the framework and libraries you&amp;rsquo;ll be using.&lt;/p&gt;
&lt;h3 id=&quot;flask&quot;&gt;Flask&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;http://flask.pocoo.org/&quot;&gt;Flask&lt;/a&gt; is a lightweight web-framework, a self-proclaimed &lt;strong&gt;microframework&lt;/strong&gt;. It comes with built-in tools for the basic tasks that a web application will perform, like routing URLs and handling HTTP requests.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve chosen to use Flask as an example for both its popularity and simplicity. However, the things you&amp;rsquo;ve learned about OAuth 2 and OIDC are not specific to Flask. In fact, even the library you&amp;rsquo;ll be using to make OAuth 2 and OIDC easier is usable in any Python code. In other words, with some minor modifications, you can take what you learn here and apply it to another framework of your choice.&lt;/p&gt;
&lt;h3 id=&quot;flask-login&quot;&gt;Flask-Login&lt;/h3&gt;
&lt;p&gt;Another tool you can use to make the handling of users easier is &lt;a href=&quot;https://flask-login.readthedocs.io/en/latest/&quot;&gt;flask_login&lt;/a&gt;, which provides &lt;strong&gt;user session management&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;This library does a few things behind the scenes and gives you some tools to help with users. Namely, it provides utilities for you to know when a user is logged in and logged out. It does this by managing a user session inside a browser cookie.&lt;/p&gt;
&lt;p&gt;It also handles the logging in and logging out of users, including the creation of database entries for those users. From the aspect of your code though, it really just makes everything a lot simpler (which you&amp;rsquo;ll see soon).&lt;/p&gt;
&lt;h3 id=&quot;oauthlib&quot;&gt;OAuthLib&lt;/h3&gt;
&lt;p&gt;There&amp;rsquo;s a common phrase that holds very true for security-related and standard-compliant code: &amp;ldquo;Don&amp;rsquo;t reinvent the wheel.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;OAuth 2 and OpenID Connect standards are complicated. Have a look at the RFC and specifications, and you&amp;rsquo;ll see. They&amp;rsquo;re dense. One mistake means that you could be opening up a vulnerability in your application.&lt;/p&gt;
&lt;p&gt;So, you are not going to be writing code to implement these standards. You&amp;rsquo;re going to use a Python package that was chosen on some very specific criteria:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;It&amp;rsquo;s a popular and generally recommended library. Lots of other packages use this library internally.&lt;/li&gt;
&lt;li&gt;It is very active, with people patching bugs frequently. &lt;/li&gt;
&lt;li&gt;It&amp;rsquo;s battle-hardened and has been around since 2012.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;There are web-framework-specific packages that use this library to more closely integrate into Flask, Django, Pyramid, and others. However, to keep the code you learn here framework-agnostic, you&amp;rsquo;ll use this library directly without any fancy wrappers.&lt;/p&gt;
&lt;h3 id=&quot;installing-dependencies&quot;&gt;Installing Dependencies&lt;/h3&gt;
&lt;p&gt;There are a number of third-party dependencies that you&amp;rsquo;ll use to make your life easier. Here&amp;rsquo;s a summary of those dependencies:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A web framework to make typical web application tasks easier (Flask)&lt;/li&gt;
&lt;li&gt;A headache-free way of managing user sessions (Flask-Login)&lt;/li&gt;
&lt;li&gt;A battle-hardened OIDC library (&lt;code&gt;oauthlib&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Additionally, you&amp;rsquo;ll use the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A database to store some information about users who log in (SQLite)&lt;/li&gt;
&lt;li&gt;An user-friendly way to send HTTP requests to Google (&lt;code&gt;requests&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;A quick way to enable running securely with &lt;code&gt;https&lt;/code&gt; locally (pyOpenSSL)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;SQLite is part of the standard Python library, but the other packages are not. So you have a couple of dependencies to install. For now, let&amp;rsquo;s just go through the creation of this application step by step.&lt;/p&gt;
&lt;p&gt;First, you&amp;rsquo;ll need to install those third-party dependencies mentioned above. You&amp;rsquo;ll do this by creating a &lt;code&gt;requirements.txt&lt;/code&gt; file with the following contents:&lt;/p&gt;
&lt;div class=&quot;highlight text&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;requests==2.21.0
Flask==1.0.2
oauthlib==3.0.1
pyOpenSSL==19.0.0
Flask-Login==0.4.1
&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; Other versions of the packages may work, but these are versions that were used during the writing and testing of this article.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;Next, you can install those dependencies using &lt;code&gt;pip&lt;/code&gt;, Python&amp;rsquo;s package installer.&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; It is generally recommended to use virtual environments if you&amp;rsquo;re going to be installing dependencies for different Python applications on your computer. See &lt;a href=&quot;https://realpython.com/python-virtual-environments-a-primer/&quot;&gt;Python Virtual Environments: A Primer&lt;/a&gt; to learn more.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;To install from the &lt;code&gt;requirements.txt&lt;/code&gt; file, run the following command in your terminal:&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;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now you&amp;rsquo;re ready to rock and roll! Let&amp;rsquo;s dig right into the code.&lt;/p&gt;
&lt;h3 id=&quot;imports-configuration-and-setup&quot;&gt;Imports, Configuration, and Setup&lt;/h3&gt;
&lt;p&gt;Start by adding a few files to support some basic database functionality and user management. These won&amp;rsquo;t be described section by section, mostly because diving into &lt;a href=&quot;https://realpython.com/tutorials/databases/&quot;&gt;Python database&lt;/a&gt; implementation details is a rabbit hole that would distract us from our goal.&lt;/p&gt;
&lt;div class=&quot;card mb-3&quot; id=&quot;collapse_card27d0f0&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;#collapse27d0f0&quot; aria-expanded=&quot;false&quot; aria-controls=&quot;collapse27d0f0&quot;&gt;db.py&lt;/button&gt; &lt;button class=&quot;btn btn-link float-right&quot; data-toggle=&quot;collapse&quot; data-target=&quot;#collapse27d0f0&quot; aria-expanded=&quot;false&quot; aria-controls=&quot;collapse27d0f0&quot;&gt;Show/Hide&lt;/button&gt;&lt;/p&gt;&lt;/div&gt;
&lt;div id=&quot;collapse27d0f0&quot; class=&quot;collapse&quot; data-parent=&quot;#collapse_card27d0f0&quot;&gt;&lt;div class=&quot;card-body&quot; markdown=&quot;1&quot;&gt;

&lt;p&gt;This file will handle some database functionality. This is almost line by line from &lt;a href=&quot;http://flask.pocoo.org/docs/1.0/tutorial/database/&quot;&gt;Flask&amp;rsquo;s official database tutorial&lt;/a&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;# http://flask.pocoo.org/docs/1.0/tutorial/database/&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;sqlite3&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;click&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;flask&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;current_app&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;g&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;flask.cli&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;with_appcontext&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;get_db&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;s2&quot;&gt;&amp;quot;db&amp;quot;&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;g&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;g&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;sqlite3&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;connect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
            &lt;span class=&quot;s2&quot;&gt;&amp;quot;sqlite_db&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;detect_types&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sqlite3&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;PARSE_DECLTYPES&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;g&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;row_factory&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sqlite3&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Row&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;g&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;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;close_db&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;e&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;db&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pop&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;db&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&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;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;db&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;n&quot;&gt;db&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;close&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_db&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;get_db&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;current_app&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;open_resource&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;schema.sql&amp;quot;&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;db&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;executescript&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;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;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;s2&quot;&gt;&amp;quot;utf8&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;

&lt;span class=&quot;nd&quot;&gt;@click&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;command&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;init-db&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;nd&quot;&gt;@with_appcontext&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;init_db_command&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;Clear the existing data and create new tables.&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;init_db&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;click&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;echo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;Initialized the database.&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;init_app&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;app&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;app&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;teardown_appcontext&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;close_db&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;app&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cli&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add_command&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;init_db_command&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 have some database utilities, you can start to think about the schema. You may notice that this code is looking for a &lt;code&gt;schema.sql&lt;/code&gt; file, which you&amp;rsquo;ll create next.&lt;/p&gt;
&lt;/div&gt;&lt;/div&gt;

&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;schema.sql&lt;/code&gt; file is just some SQL that will create a user table in our database. You can see the fields you&amp;rsquo;ll be storing per user in this file.&lt;/p&gt;
&lt;div class=&quot;card mb-3&quot; id=&quot;collapse_card435202&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;#collapse435202&quot; aria-expanded=&quot;false&quot; aria-controls=&quot;collapse435202&quot;&gt;schema.sql&lt;/button&gt; &lt;button class=&quot;btn btn-link float-right&quot; data-toggle=&quot;collapse&quot; data-target=&quot;#collapse435202&quot; aria-expanded=&quot;false&quot; aria-controls=&quot;collapse435202&quot;&gt;Show/Hide&lt;/button&gt;&lt;/p&gt;&lt;/div&gt;
&lt;div id=&quot;collapse435202&quot; class=&quot;collapse&quot; data-parent=&quot;#collapse_card435202&quot;&gt;&lt;div class=&quot;card-body&quot; markdown=&quot;1&quot;&gt;

&lt;p&gt;Here you have a single table, &lt;code&gt;user&lt;/code&gt;, which will house a few things related to users (their name, the email they log in with, and their profile picture from Google):&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;TABLE&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;user&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;id&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;TEXT&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;PRIMARY&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;KEY&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;nb&quot;&gt;TEXT&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;email&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;TEXT&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;UNIQUE&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;profile_pic&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;TEXT&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;NULL&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The code in the &lt;code&gt;db.py&lt;/code&gt; file will actually execute this SQL to create the table in your database.&lt;/p&gt;
&lt;/div&gt;&lt;/div&gt;

&lt;/div&gt;
&lt;p&gt;This next file contains our &lt;code&gt;User&lt;/code&gt; class, which will store and retrieve information from the database. The name, email, and profile picture will all be retrieved from Google, which you&amp;rsquo;ll see later on in the article.&lt;/p&gt;
&lt;div class=&quot;card mb-3&quot; id=&quot;collapse_card784fcf&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;#collapse784fcf&quot; aria-expanded=&quot;false&quot; aria-controls=&quot;collapse784fcf&quot;&gt;user.py&lt;/button&gt; &lt;button class=&quot;btn btn-link float-right&quot; data-toggle=&quot;collapse&quot; data-target=&quot;#collapse784fcf&quot; aria-expanded=&quot;false&quot; aria-controls=&quot;collapse784fcf&quot;&gt;Show/Hide&lt;/button&gt;&lt;/p&gt;&lt;/div&gt;
&lt;div id=&quot;collapse784fcf&quot; class=&quot;collapse&quot; data-parent=&quot;#collapse_card784fcf&quot;&gt;&lt;div class=&quot;card-body&quot; markdown=&quot;1&quot;&gt;

&lt;p&gt;The &lt;code&gt;User&lt;/code&gt; class has methods to get an existing user from the database and create a new user:&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;flask_login&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;UserMixin&lt;/span&gt;

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

&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;UserMixin&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;n&quot;&gt;id_&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;email&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;profile_pic&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;id&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;id_&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;name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&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;email&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;email&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;profile_pic&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;profile_pic&lt;/span&gt;

    &lt;span class=&quot;nd&quot;&gt;@staticmethod&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;user_id&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;get_db&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;user&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;execute&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
            &lt;span class=&quot;s2&quot;&gt;&amp;quot;SELECT * FROM user WHERE id = ?&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;user_id&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;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fetchone&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;ow&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;user&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;kc&quot;&gt;None&lt;/span&gt;

        &lt;span class=&quot;n&quot;&gt;user&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;id_&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;user&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;name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;user&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;email&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;user&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;profile_pic&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;user&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;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;user&lt;/span&gt;

    &lt;span class=&quot;nd&quot;&gt;@staticmethod&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;create&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;id_&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;email&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;profile_pic&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;get_db&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;execute&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
            &lt;span class=&quot;s2&quot;&gt;&amp;quot;INSERT INTO user (id, name, email, profile_pic) &amp;quot;&lt;/span&gt;
            &lt;span class=&quot;s2&quot;&gt;&amp;quot;VALUES (?, ?, ?, ?)&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;id_&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;email&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;profile_pic&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;db&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 executes SQL statements against the database, which is retrieved from the &lt;code&gt;get_db()&lt;/code&gt; function from the previous &lt;code&gt;db.py&lt;/code&gt; file. Each new user results in the insertion of an additional row in the database.&lt;/p&gt;
&lt;/div&gt;&lt;/div&gt;

&lt;/div&gt;
&lt;p&gt;After you&amp;rsquo;ve created the &lt;code&gt;db.py&lt;/code&gt;, &lt;code&gt;schema.sql&lt;/code&gt;, and &lt;code&gt;user.py&lt;/code&gt; files from the above code, you can create a new &lt;code&gt;app.py&lt;/code&gt; file. Add to it the following imports:&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;# Python standard libraries&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;json&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;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;sqlite3&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Third-party libraries&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;flask&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Flask&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;redirect&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;url_for&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;flask_login&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;LoginManager&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;current_user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;login_required&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;login_user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;logout_user&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;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;oauthlib.oauth2&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;WebApplicationClient&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;c1&quot;&gt;# Internal imports&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;db&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;init_db_command&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;user&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;User&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You&amp;rsquo;ll use all these later on, so it&amp;rsquo;s not so important to understand each of them at the moment. The next portion in your &lt;code&gt;app.py&lt;/code&gt; is some configuration:&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;# Configuration&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;GOOGLE_CLIENT_ID&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&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;environ&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;GOOGLE_CLIENT_ID&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&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;GOOGLE_CLIENT_SECRET&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&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;environ&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;GOOGLE_CLIENT_SECRET&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&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;GOOGLE_DISCOVERY_URL&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;https://accounts.google.com/.well-known/openid-configuration&amp;quot;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Here&amp;rsquo;s how you&amp;rsquo;ll store the Google Client ID and Client Secret, which you should have created earlier in the article. These will be used later in the OIDC flow.&lt;/p&gt;
&lt;p&gt;Your application will try to get the client credentials by reading environmental variables. There are a couple reasons for this:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;You don&amp;rsquo;t have to change your code later if you want to use different credentials, you just have to update the environment.&lt;/li&gt;
&lt;li&gt;You can&amp;rsquo;t accidentally commit your secret credentials to GitHub (or another public repository).&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Lots of people accidentally commit secrets to public repositories, posing a pretty serious security risk. It&amp;rsquo;s better to protect against that by using environmental variables.&lt;/p&gt;
&lt;div class=&quot;alert alert-primary&quot; role=&quot;alert&quot;&gt;
&lt;p&gt;&lt;strong&gt;Tip:&lt;/strong&gt; You can set your client credentials as environmental variables in Linux bash terminal and Mac OS X terminal using &lt;code&gt;export GOOGLE_CLIENT_ID=your_client_id&lt;/code&gt; (similarly for &lt;code&gt;GOOGLE_CLIENT_SECRET&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re on Windows, you can use &lt;code&gt;set GOOGLE_CLIENT_ID=your_client_id&lt;/code&gt; in Command Prompt.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;Alternatively, you &lt;em&gt;could&lt;/em&gt; paste the strings directly here and store them in these variables.
&lt;strong&gt;However&lt;/strong&gt;, the client secret should &lt;strong&gt;not&lt;/strong&gt; be shared or committed to any public repository. In other words, be very careful not to check in this file if you paste your real client credentials in here.&lt;/p&gt;
&lt;p&gt;Finally, below is some code with global variables and some naive database initialization logic. Most of this, other than the database initialization, is the standard way to set up Flask, Flask-Login, and OAuthLib, which you read about earlier:&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;# Flask app setup&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;app&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Flask&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;vm&quot;&gt;__name__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;app&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;secret_key&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&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;environ&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;SECRET_KEY&amp;quot;&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;n&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;urandom&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;24&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# User session management setup&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# https://flask-login.readthedocs.io/en/latest&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;login_manager&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LoginManager&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;login_manager&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;init_app&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;app&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Naive database setup&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;try&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;init_db_command&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;except&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sqlite3&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;OperationalError&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# Assume it&amp;#39;s already been created&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;pass&lt;/span&gt;

&lt;span class=&quot;hll&quot;&gt;&lt;span class=&quot;c1&quot;&gt;# OAuth 2 client setup&lt;/span&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;WebApplicationClient&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GOOGLE_CLIENT_ID&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Flask-Login helper to retrieve a user from our db&lt;/span&gt;
&lt;span class=&quot;nd&quot;&gt;@login_manager&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;user_loader&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;load_user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;user_id&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;User&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;user_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Note that you are already using the Client ID from Google to initialize our &lt;code&gt;oauthlib&lt;/code&gt; client in the &lt;code&gt;WebApplicationClient&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;You can create another environment variable &lt;code&gt;SECRET_KEY&lt;/code&gt; that &lt;a href=&quot;http://flask.pocoo.org/docs/1.0/api/#flask.Flask.secret_key&quot;&gt;Flask and Flask-Login will use&lt;/a&gt; to cryptographically sign cookies and other items.&lt;/p&gt;
&lt;h3 id=&quot;web-application-endpoints&quot;&gt;Web Application Endpoints&lt;/h3&gt;
&lt;p&gt;Now, for the fun stuff. You&amp;rsquo;re going to write four endpoints for your web application:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;One for the homepage&lt;/li&gt;
&lt;li&gt;One for beginning the user login process&lt;/li&gt;
&lt;li&gt;One for a callback where Google will redirect to after a user logs in&lt;/li&gt;
&lt;li&gt;One for logging out&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;These endpoints will be defined by different URLs on your application with very creative names:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Homepage:&lt;/strong&gt; &lt;code&gt;/&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Login:&lt;/strong&gt; &lt;code&gt;/login&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Login Callback:&lt;/strong&gt; &lt;code&gt;/login/callback&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Logout:&lt;/strong&gt; &lt;code&gt;/logout&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Of course, you may want to add additional pages and functionality later. The end result of this application will be totally extensible to add anything you want to it.&lt;/p&gt;
&lt;p&gt;You&amp;rsquo;ll add all the following code for these endpoints into the &lt;code&gt;app.py&lt;/code&gt; file. Let&amp;rsquo;s take a look at each of these endpoints&amp;rsquo; code, one at a time.&lt;/p&gt;
&lt;h4 id=&quot;homepage&quot;&gt;Homepage&lt;/h4&gt;
&lt;p&gt;This is nothing fancy visually, but you&amp;rsquo;ll add some neat logic to display something different if a user is logged in. When they&amp;rsquo;re not logged in, a link will appear that says &lt;em&gt;Google Login&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Pressing the link will redirect them to your &lt;code&gt;/login&lt;/code&gt; endpoint, which will initiate the login flow. After a successful login, the homepage will now display both the user&amp;rsquo;s Google email and their public Google profile picture!&lt;/p&gt;
&lt;p&gt;Without further ado, you can start adding more code to your &lt;code&gt;app.py&lt;/code&gt; 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;nd&quot;&gt;@app&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;route&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;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;index&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;current_user&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;is_authenticated&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;p&quot;&gt;(&lt;/span&gt;
            &lt;span class=&quot;s2&quot;&gt;&amp;quot;&amp;lt;p&amp;gt;Hello, &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;! You&amp;#39;re logged in! Email: &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;lt;/p&amp;gt;&amp;quot;&lt;/span&gt;
            &lt;span class=&quot;s2&quot;&gt;&amp;quot;&amp;lt;div&amp;gt;&amp;lt;p&amp;gt;Google Profile Picture:&amp;lt;/p&amp;gt;&amp;quot;&lt;/span&gt;
            &lt;span class=&quot;s1&quot;&gt;&amp;#39;&amp;lt;img src=&amp;quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{}&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;quot; alt=&amp;quot;Google profile pic&amp;quot;&amp;gt;&amp;lt;/img&amp;gt;&amp;lt;/div&amp;gt;&amp;#39;&lt;/span&gt;
            &lt;span class=&quot;s1&quot;&gt;&amp;#39;&amp;lt;a class=&amp;quot;button&amp;quot; href=&amp;quot;/logout&amp;quot;&amp;gt;Logout&amp;lt;/a&amp;gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;format&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;current_user&lt;/span&gt;&lt;span class=&quot;o&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;current_user&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;email&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;current_user&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;profile_pic&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;k&quot;&gt;else&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;s1&quot;&gt;&amp;#39;&amp;lt;a class=&amp;quot;button&amp;quot; href=&amp;quot;/login&amp;quot;&amp;gt;Google Login&amp;lt;/a&amp;gt;&amp;#39;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You&amp;rsquo;ll note that you&amp;rsquo;re returning HTML as a string, which Flask will be able to serve. The &lt;code&gt;current_user.is_authenticated&lt;/code&gt; is a lovely addition of the &lt;code&gt;Flask-Login&lt;/code&gt; library. It&amp;rsquo;s a straightforward way to determine if the current user interacting with your application is logged in or not. This lets you apply conditional logic. In this case, it&amp;rsquo;s displaying some information you have saved about the user if they&amp;rsquo;re logged in.&lt;/p&gt;
&lt;p&gt;You can get fields from your database entry for the user by just accessing them as attributes on the &lt;code&gt;current_user&lt;/code&gt; object, such as &lt;code&gt;current_user.email&lt;/code&gt;. This is another addition of &lt;code&gt;Flask-Login&lt;/code&gt;.&lt;/p&gt;
&lt;h4 id=&quot;login&quot;&gt;Login&lt;/h4&gt;
&lt;p&gt;Now let&amp;rsquo;s get to the OAuth 2 flow. The &lt;em&gt;Google Login&lt;/em&gt; button from above will redirect to this endpoint. The first step in the flow is to figure out where Google&amp;rsquo;s OAuth 2 Authorization endpoint is.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s where the lines between what&amp;rsquo;s defined by OAuth 2 and by OpenID Connect (OIDC) start to blur. As discussed previously, OIDC has a standard endpoint for a &lt;strong&gt;provider configuration&lt;/strong&gt;, which contains a bunch of OAuth 2 and OIDC information. The document with that information is served from a standard endpoint everywhere, &lt;code&gt;.well-known/openid-configuration&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Assuming you copied the previous code that defined &lt;code&gt;GOOGLE_DISCOVERY_URL&lt;/code&gt;, here&amp;rsquo;s a quick, naive, function for retrieving Google&amp;rsquo;s provider configuration:&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;get_google_provider_cfg&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;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;GOOGLE_DISCOVERY_URL&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;json&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&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;Tip:&lt;/strong&gt; To make this more robust, you should add error handling to the Google API call, just in case Google&amp;rsquo;s API returns a failure and not the valid provider configuration document.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;The field from the provider configuration document you need is called &lt;code&gt;authorization_endpoint&lt;/code&gt;. This will contain the URL you need to use to initiate the OAuth 2 flow with Google from your client application.&lt;/p&gt;
&lt;p&gt;You can put all that logic together with 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;nd&quot;&gt;@app&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;route&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;/login&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;login&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# Find out what URL to hit for Google login&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;google_provider_cfg&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;get_google_provider_cfg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;authorization_endpoint&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;google_provider_cfg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;authorization_endpoint&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;# Use library to construct the request for Google login and provide&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# scopes that let you retrieve user&amp;#39;s profile from Google&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;request_uri&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;prepare_request_uri&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;authorization_endpoint&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;redirect_uri&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;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;base_url&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;/callback&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;scope&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;openid&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;email&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;profile&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;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;redirect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;request_uri&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Luckily, &lt;code&gt;oauthlib&lt;/code&gt; makes the actual request to Google easier. You used your pre-configured &lt;code&gt;client&lt;/code&gt; that you already gave your Google Client ID to. Next, you provided the redirect you want Google to use. Finally, you asked Google for a number of OAuth 2 &lt;code&gt;scopes&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;You can think of each scope as a separate piece of user information. In your case, you&amp;rsquo;re asking for the user&amp;rsquo;s email and basic profile information from Google. The user will, of course, have to consent to give you this information.&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;openid&lt;/code&gt; is a required scope to tell Google to initiate the OIDC flow, which will authenticate the user by having them log in. OAuth 2 doesn&amp;rsquo;t actually standardize how authentication happens, so this is necessary for our flow in this case.&lt;/p&gt;
&lt;/div&gt;
&lt;h4 id=&quot;login-callback&quot;&gt;Login Callback&lt;/h4&gt;
&lt;p&gt;Let&amp;rsquo;s do this one in pieces, since it&amp;rsquo;s a bit more involved than the previous few endpoints.&lt;/p&gt;
&lt;p&gt;Once you redirect to Google&amp;rsquo;s authorization endpoint, a lot happens on Google&amp;rsquo;s end.&lt;/p&gt;
&lt;p&gt;The login endpoint on your application is the jumping point for all of Google&amp;rsquo;s work authenticating the user and asking for consent. Once the user logs in with Google and agrees to share their email and basic profile information with your application, Google generates a unique code that it sends back to your application.&lt;/p&gt;
&lt;p&gt;As a reminder, here are the OIDC steps you read about earlier:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;You register a third-party application as a client to the provider.&lt;/li&gt;
&lt;li&gt;The client sends a request to the provider&amp;rsquo;s &lt;code&gt;authorization&lt;/code&gt; URL.&lt;/li&gt;
&lt;li&gt;The provider asks the user to authenticate (prove who they are).&lt;/li&gt;
&lt;li&gt;The provider asks the user to consent to the client acting on their behalf.&lt;/li&gt;
&lt;li&gt;The provider sends the client a unique authorization code&lt;/li&gt;
&lt;li&gt;The client sends the authorization code back to the provider&amp;rsquo;s &lt;code&gt;token&lt;/code&gt; URL&lt;/li&gt;
&lt;li&gt;The provider sends the client tokens to use with other URLs on behalf of the user&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;When Google sends back that unique code, it&amp;rsquo;ll be sending it to this login callback endpoint on your application. So your first step is to define the endpoint and get that &lt;code&gt;code&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;nd&quot;&gt;@app&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;route&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;/login/callback&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;callback&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# Get authorization code Google sent back to you&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;code&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;o&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;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;code&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 next thing you&amp;rsquo;re going to do is send that code back to Google&amp;rsquo;s &lt;code&gt;token&lt;/code&gt; endpoint. After Google verifies your client credentials, they will send you back tokens that will allow you to authenticate to other Google endpoints on behalf of the user, including the &lt;code&gt;userinfo&lt;/code&gt; endpoint you read about earlier. In your case, you only asked to view basic profile information, so that&amp;rsquo;s the only thing you can do with the tokens.&lt;/p&gt;
&lt;p&gt;To start with, you need to figure out what Google&amp;rsquo;s &lt;code&gt;token&lt;/code&gt; endpoint is. You&amp;rsquo;ll use the provider configuration document again:&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;# Find out what URL to hit to get tokens that allow you to ask for&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# things on behalf of a user&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;google_provider_cfg&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;get_google_provider_cfg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;token_endpoint&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;google_provider_cfg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;token_endpoint&amp;quot;&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;oauthlib&lt;/code&gt; comes to your rescue a few times in this next block of code. First, you need to construct the token request. Once the request is constructed, you&amp;rsquo;ll use the &lt;code&gt;requests&lt;/code&gt; library to actually send it out. Then &lt;code&gt;oauthlib&lt;/code&gt;, once again, will help you with parsing the tokens from the response:&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;# Prepare and send a request to get tokens! Yay tokens!&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;token_url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;headers&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;client&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;prepare_token_request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;token_endpoint&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;authorization_response&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;o&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;redirect_url&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;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;base_url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;code&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;code&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;token_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;post&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;token_url&lt;/span&gt;&lt;span class=&quot;p&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;headers&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;body&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;auth&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;GOOGLE_CLIENT_ID&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;GOOGLE_CLIENT_SECRET&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;c1&quot;&gt;# Parse the tokens!&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;parse_request_body_response&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dumps&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;token_response&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;json&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 have the necessary tools to get the user&amp;rsquo;s profile information, you need to ask Google for it. Luckily, OIDC defines a user information endpoint, and its URL for a given provider is standardized in the provider configuration. You can get the location by checking the &lt;code&gt;userinfo_endpoint&lt;/code&gt; field in the provider configuration document. Then you can use &lt;code&gt;oauthlib&lt;/code&gt; to add the token to your request and use &lt;code&gt;requests&lt;/code&gt; to send it out:&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;# Now that you have tokens (yay) let&amp;#39;s find and hit the URL&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# from Google that gives you the user&amp;#39;s profile information,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# including their Google profile image and email&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;userinfo_endpoint&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;google_provider_cfg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;userinfo_endpoint&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;uri&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;headers&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;client&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add_token&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;userinfo_endpoint&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;userinfo_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;uri&lt;/span&gt;&lt;span class=&quot;p&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;headers&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;body&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The next step in your journey is to parse the response from the &lt;code&gt;userinfo&lt;/code&gt; endpoint. Google uses an optional field, &lt;code&gt;email_verified&lt;/code&gt;, to confirm that not only has the user created an account, but they&amp;rsquo;ve verified the email address to complete the account creation. It&amp;rsquo;s generally safe to conditionally check for this verification, as it&amp;rsquo;s another layer of security that Google offers.&lt;/p&gt;
&lt;p&gt;That being said, you&amp;rsquo;ll check for that, and if Google says the user is verified, then you&amp;rsquo;ll parse their information. The 4 pieces of basic profile information you&amp;rsquo;ll use are:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;sub&lt;/code&gt;:&lt;/strong&gt; the subject, a unique identifier for the user in Google&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;email&lt;/code&gt;:&lt;/strong&gt; the user&amp;rsquo;s Google email address&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;picture&lt;/code&gt;:&lt;/strong&gt; the user&amp;rsquo;s public profile picture in Google&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;given_name&lt;/code&gt;:&lt;/strong&gt; the user&amp;rsquo;s first and last name in Google&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;All of that parsing results in 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;c1&quot;&gt;# You want to make sure their email is verified.&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# The user authenticated with Google, authorized your&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# app, and now you&amp;#39;ve verified their email through Google!&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;userinfo_response&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;json&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;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;email_verified&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;unique_id&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;userinfo_response&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;sub&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;users_email&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;userinfo_response&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;email&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;picture&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;userinfo_response&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;picture&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;users_name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;userinfo_response&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;given_name&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&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;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;User email not available or not verified by Google.&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;400&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The final steps in this callback are:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Create a user in your database with the information you just got from Google&lt;/li&gt;
&lt;li&gt;Begin a user session by logging that user in&lt;/li&gt;
&lt;li&gt;Send user back to the homepage (where you&amp;rsquo;ll now display their public profile information)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The code to fulfill those steps is as follows:&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;# Create a user in your db with the information provided&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# by Google&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;user&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;id_&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;unique_id&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;n&quot;&gt;users_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;email&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;users_email&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;profile_pic&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;picture&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Doesn&amp;#39;t exist? Add it to the database.&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;User&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;unique_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;create&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;unique_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;users_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;users_email&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;picture&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Begin user session by logging the user in&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;login_user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Send user back to homepage&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;redirect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;url_for&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;index&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;So what you&amp;rsquo;re doing here is creating a new row in your database for the user if they don&amp;rsquo;t already exist. Then, you&amp;rsquo;re starting a session using Flask-Login.&lt;/p&gt;
&lt;h4 id=&quot;logout&quot;&gt;Logout&lt;/h4&gt;
&lt;p&gt;The logout endpoint is much less code than the last few endpoints. You just call a logout function and redirect back to the homepage. Done and done. Here it is:&lt;/p&gt;
&lt;div class=&quot;highlight python&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;nd&quot;&gt;@app&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;route&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;/logout&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;nd&quot;&gt;@login_required&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;logout&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;logout_user&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;redirect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;url_for&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;index&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 &lt;code&gt;@login_required&lt;/code&gt; &lt;a href=&quot;https://realpython.com/primer-on-python-decorators/&quot;&gt;decorator&lt;/a&gt; is something important to mention here. It&amp;rsquo;s another tool from the &lt;code&gt;Flask-Login&lt;/code&gt; toolbox and will make sure that only logged in users can access this endpoint. You can use this if only logged in users should be accessing something. In this case, only logged in users can log out.&lt;/p&gt;
&lt;h3 id=&quot;testing-your-application-locally&quot;&gt;Testing Your Application Locally&lt;/h3&gt;
&lt;p&gt;You can run your Flask application on your local computer to test the login flow by adding some final code to &lt;code&gt;app.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;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;n&quot;&gt;app&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ssl_context&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;adhoc&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You can run your Flask application with the following command in your terminal:&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 app.py
&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; Because of the naive database initialization logic, the first time you run this command, it will create the database. To start your app, you have to run the same command &lt;em&gt;again&lt;/em&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;Flask should print to your terminal where it&amp;rsquo;s running the development server. It should be &lt;code&gt;https://127.0.0.1:5000/&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Note that Flask&amp;rsquo;s development server is running locally &lt;em&gt;and&lt;/em&gt; using &lt;code&gt;https&lt;/code&gt; to ensure an encrypted connection with Google. This is achieved by the &lt;code&gt;ssl_context=&quot;adhoc&quot;&lt;/code&gt; argument to &lt;code&gt;app.run&lt;/code&gt; in the code above. This requires you to have the package &lt;code&gt;PyOpenSSL&lt;/code&gt; installed.&lt;/p&gt;
&lt;p&gt;The downside is that the certificate used is generated on the fly, so when you go to &lt;code&gt;https://127.0.0.1:5000/&lt;/code&gt; in your browser, it will probably give you a big warning screen about your connection being insecure or not private. You can effectively ignore these warnings.&lt;/p&gt;
&lt;p&gt;Once past the warning screen, you should see a single button that says &lt;em&gt;Google Login&lt;/em&gt;. Pressing it will send you to the official Google login. After you log in, Google will prompt you to consent to the &amp;ldquo;third-party application&amp;rdquo; getting access to your email and profile information.&lt;/p&gt;
&lt;p&gt;After consenting, you&amp;rsquo;ll be redirected back to your Flask application, where the page should show your Google email and public profile picture! Finally, a &lt;em&gt;Logout&lt;/em&gt; button allows you to, well, log out.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Allowing users to use their existing accounts to log into your web application has many benefits. Most importantly, the security and complexity of account management does not have to rest on your shoulders. This frees you up to write your fancy new web application without worrying about the nitty gritty details of two-factor authentication and the like.&lt;/p&gt;
&lt;p&gt;The application you made in this article is a great starting point. You can click the box below to get the code:&lt;/p&gt;
&lt;div class=&quot;alert alert-warning&quot; role=&quot;alert&quot;&gt;&lt;p&gt;&lt;strong&gt;Download Sample Project:&lt;/strong&gt; &lt;a href=&quot;https://realpython.com/optins/view/google-login-project/&quot; class=&quot;alert-link&quot; data-toggle=&quot;modal&quot; data-target=&quot;#modal-google-login-project&quot; data-focus=&quot;false&quot;&gt;Click here to download the code for the Flask application with Google login you&#39;ll build in this article.&lt;/a&gt;&lt;/p&gt;&lt;/div&gt;

&lt;p&gt;Your next step could be to do the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Rework the database initialization to happen separately from running the application&lt;/li&gt;
&lt;li&gt;Separate out the HTML/CSS from the Python code for easier management:&lt;ul&gt;
&lt;li&gt;You could use &lt;a href=&quot;http://flask.pocoo.org/docs/1.0/tutorial/templates/&quot;&gt;templates&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;You could also load static files (like JS and CSS) &lt;a href=&quot;http://flask.pocoo.org/docs/1.0/quickstart/#static-files&quot;&gt;from elsewhere&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Host your application in the cloud&lt;/li&gt;
&lt;li&gt;Purchase a domain name&lt;/li&gt;
&lt;li&gt;Use a real SSL certificate and get rid of that pesky warning&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In this article, you&amp;rsquo;ve gone through the basics of OAuth 2 and OpenID Connect. You&amp;rsquo;ve seen how to use well-known Python packages to create a web application that allows users to log in with their existing Google account. Most importantly, you have example code that serves as a great starting point for your next web application!&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 Write Pythonic Loops</title>
      <id>https://realpython.com/courses/how-to-write-pythonic-loops/</id>
      <link href="https://realpython.com/courses/how-to-write-pythonic-loops/"/>
      <updated>2019-07-16T14:00:00+00:00</updated>
      <summary>In this course, you&#39;ll see how you can make your loops more Pythonic if you&#39;re coming to Python from a C-style language. You&#39;ll learn how you can get the most out of using range(), xrange(), and enumerate(). You&#39;ll also see how you can avoid having to keep track of loop indexes manually.</summary>
      <content type="html">
        &lt;p&gt;One of the easiest ways to spot a developer who has a background in C-style languages and only recently picked up Python is to look at how they loop through a list. In this course, you&amp;rsquo;ll learn how to take a C-style (Java, PHP, C, C++) loop and turn it into the sort of loop a Python developer would write.&lt;/p&gt;
&lt;p&gt;You can use these techniques to refactor your existing Python &lt;a href=&quot;https://realpython.com/python-for-loop/&quot;&gt;&lt;code&gt;for&lt;/code&gt; loops&lt;/a&gt; and &lt;a href=&quot;https://realpython.com/python-while-loop/&quot;&gt;&lt;code&gt;while&lt;/code&gt; loops&lt;/a&gt; in order to make them easier to read and more maintainable. You&amp;rsquo;ll learn how to use Python&amp;rsquo;s &lt;a href=&quot;https://realpython.com/python-range/&quot;&gt;&lt;code&gt;range()&lt;/code&gt;, &lt;code&gt;xrange()&lt;/code&gt;&lt;/a&gt;, and &lt;code&gt;enumerate()&lt;/code&gt; built-ins to refactor your loops and how to avoid having to keep track of loop indexes manually.&lt;/p&gt;
&lt;p&gt;The main takeaways in this tutorial are that:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Writing C-style loops in Python is considered not &lt;a href=&quot;https://realpython.com/learning-paths/writing-pythonic-code/&quot;&gt;Pythonic&lt;/a&gt;. Avoid managing loop indexes and stop conditions manually if possible.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Python’s &lt;code&gt;for&lt;/code&gt; loops are really “for each” loops that can iterate over items from a container or sequence directly.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&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>Real Python at PyCon US 2019</title>
      <id>https://realpython.com/real-python-pycon-us/</id>
      <link href="https://realpython.com/real-python-pycon-us/"/>
      <updated>2019-07-15T14:00:00+00:00</updated>
      <summary>Join the Real Python team as we reminisce about our first PyCon together, and for some of us, our first PyCon ever. Find out what our highs and lows were, and learn why none of us can get the Golden Girls theme tune out of our heads 🤦‍♂️</summary>
      <content type="html">
        &lt;p&gt;There are many PyCons all over the world each year, but the biggest of them all is &lt;a href=&quot;https://us.pycon.org/2019/&quot;&gt;PyCon US (United States)&lt;/a&gt;. This year, over 3000 Pythonistas descended on Cleveland, Ohio, to learn, collaborate, contribute, and meet old and new friends alike. I&amp;rsquo;m sure many of you are already aware of what PyCon US is, but if not, then I would suggest reading our &lt;a href=&quot;https://realpython.com/pycon-guide/&quot;&gt;guide to PyCon&lt;/a&gt; to learn more.&lt;/p&gt;
&lt;h2 id=&quot;our-first-pycon-together&quot;&gt;Our First PyCon Together&lt;/h2&gt;
&lt;p&gt;This year, &lt;em&gt;Real Python&lt;/em&gt; was afforded the opportunity to join other content creators at the &lt;a href=&quot;https://blog.jetbrains.com/pycharm/2019/04/content-creators-at-the-pycharm-pycon-booth/&quot;&gt;PyCharm Content Creators booth&lt;/a&gt;, where we got to spend some time meeting readers and members of the &lt;em&gt;Real Python&lt;/em&gt; community. Oh, and we gave out a ton of &lt;em&gt;Real Python&lt;/em&gt; stickers, and we ran out of stock completely! Did you get yours?&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://files.realpython.com/media/RP-team-pycon-2019.7067a9924fba.jpg&quot; target=&quot;_blank&quot;&gt;&lt;img class=&quot;img-fluid mx-auto d-block &quot; src=&quot;https://files.realpython.com/media/RP-team-pycon-2019.7067a9924fba.jpg&quot; width=&quot;1024&quot; height=&quot;768&quot; srcset=&quot;https://robocrop.realpython.net/?url=https%3A//files.realpython.com/media/RP-team-pycon-2019.7067a9924fba.jpg&amp;amp;w=256&amp;amp;sig=5251b990773e171c89168416cd0d8f16990d0439 256w, https://robocrop.realpython.net/?url=https%3A//files.realpython.com/media/RP-team-pycon-2019.7067a9924fba.jpg&amp;amp;w=512&amp;amp;sig=85891d492951b53d63eb43bc1036dd1c29e36fe6 512w, https://files.realpython.com/media/RP-team-pycon-2019.7067a9924fba.jpg 1024w&quot; sizes=&quot;75vw&quot; alt=&quot;Real Python Team Photo at PyCon 2019&quot;/&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The team was also excited for our authors &lt;a href=&quot;https://realpython.com/team/gahjelle/&quot;&gt;Geir Arne Hjelle&lt;/a&gt; and &lt;a href=&quot;https://realpython.com/team/ashaw/&quot;&gt;Anthony Shaw&lt;/a&gt;, who were also there as speakers. You can catch the recordings of their talks on &lt;a href=&quot;https://www.youtube.com/watch?v=98s9YfoXB68&quot;&gt;Plugins: Adding Flexibility to Your Apps&lt;/a&gt; and &lt;a href=&quot;https://www.youtube.com/watch?v=dqdsNoApJ80&amp;amp;t=3s&quot;&gt;Wily Python: Writing simpler and more maintainable Python&lt;/a&gt; on the PyCon YouTube channel.&lt;/p&gt;
&lt;p&gt;We were also lucky enough to be able to arrange a &lt;em&gt;Real Python&lt;/em&gt; open space at PyCon for our readers. We had a phenomenal turnout, with 30 people in attendance. &lt;/p&gt;
&lt;p&gt;It was a great opportunity for us to not only get to shake your hands and thank you for helping us with your encouragement and feedback but also to make sure we can continue to push and produce better and better content. Listening to the feedback from those who attended was an amazing experience, and we will be taking some of the ideas generated going forward to help us deliver a better reading and learning experience to you.&lt;/p&gt;
&lt;p&gt;Despite the daily conversation in the member and staff Slack groups, most of the &lt;em&gt;Real Python&lt;/em&gt; team had never met each other in person. Meeting my colleagues face to face and sharing a meal or beer with them was definitely one of the highlights of the whole conference for me personally. &lt;/p&gt;
&lt;p&gt;But I decided to ask the rest of the team about their experience, in hopes that we could come up with some helpful advice or actionable tips for you in case you have yet to attend your first PyCon. &lt;/p&gt;
&lt;p&gt;I asked the same three questions to a few of the team members who attended PyCon and collated their answers below. The questions were:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Can you briefly tell us who you are and what you do, in and out of &lt;em&gt;Real Python&lt;/em&gt;? Was this your first PyCon? If so, what made 2019 the year you decided to go for the first time?&lt;/li&gt;
&lt;li&gt;What were the highlights of your PyCon? What memories will you have of PyCon 2019?&lt;/li&gt;
&lt;li&gt;There is so much to do at PyCon that it&amp;rsquo;s impossible to do everything. What was something you didn&amp;rsquo;t get the chance to do but wish you had?&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;a href=&quot;https://files.realpython.com/media/pycon-sign-airport.5b9e3469ef8e.jpg&quot; target=&quot;_blank&quot;&gt;&lt;img class=&quot;img-fluid mx-auto d-block &quot; src=&quot;https://files.realpython.com/media/pycon-sign-airport.5b9e3469ef8e.jpg&quot; width=&quot;3414&quot; height=&quot;2350&quot; srcset=&quot;https://robocrop.realpython.net/?url=https%3A//files.realpython.com/media/pycon-sign-airport.5b9e3469ef8e.jpg&amp;amp;w=853&amp;amp;sig=237744ea7e399000486cbda840b9d3bde306307e 853w, https://robocrop.realpython.net/?url=https%3A//files.realpython.com/media/pycon-sign-airport.5b9e3469ef8e.jpg&amp;amp;w=1707&amp;amp;sig=3f49a725af79b48c1ee5ed2be5249039a077ab22 1707w, https://files.realpython.com/media/pycon-sign-airport.5b9e3469ef8e.jpg 3414w&quot; sizes=&quot;75vw&quot; alt=&quot;Welcome to Cleveland PyCon 2019&quot;/&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;team-interviews&quot;&gt;Team Interviews&lt;/h2&gt;
&lt;p&gt;Without further ado, let&amp;rsquo;s see what they had to say.&lt;/p&gt;
&lt;h3 id=&quot;jim-anderson&quot;&gt;Jim Anderson&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://files.realpython.com/media/jima.0b8f990b951a.jpg&quot; target=&quot;_blank&quot;&gt;&lt;img class=&quot;img-fluid w-25 rounded-circle float-right ml-3&quot; src=&quot;https://files.realpython.com/media/jima.0b8f990b951a.jpg&quot; width=&quot;700&quot; height=&quot;700&quot; srcset=&quot;https://robocrop.realpython.net/?url=https%3A//files.realpython.com/media/jima.0b8f990b951a.jpg&amp;amp;w=175&amp;amp;sig=e53eede9030c51f37a7ec1620965b715d909a184 175w, https://robocrop.realpython.net/?url=https%3A//files.realpython.com/media/jima.0b8f990b951a.jpg&amp;amp;w=350&amp;amp;sig=62a26897ded6f8732a0b21adc788637a42de2ca8 350w, https://files.realpython.com/media/jima.0b8f990b951a.jpg 700w&quot; sizes=&quot;75vw&quot; alt=&quot;Jim Anderson&quot;/&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m &lt;a href=&quot;https://realpython.com/team/janderson/&quot;&gt;Jim Anderson&lt;/a&gt;, and I&amp;rsquo;m an embedded firmware developer by day, mainly working in C++ to produce video security cameras. I get to do a bit of Python at work as well. At &lt;em&gt;Real Python&lt;/em&gt;, I&amp;rsquo;m an author and a technical reviewer, generally tending towards articles that are either low-level, tool related, or general CS topics.&lt;/p&gt;
&lt;p&gt;This was my first PyCon. I finally decided to go just due to the excitement I was seeing about it in the &lt;em&gt;Real Python&lt;/em&gt; community. Folks that I knew who had been previously talked it up so much. They were right.&lt;/p&gt;
&lt;p&gt;There were so many highlights! Getting to finally meet some of my &lt;em&gt;Real Python&lt;/em&gt; co-workers was very cool, of course, as was hanging out in the content-creators section of the PyCharm booth. (Thanks, JetBrains!) &lt;/p&gt;
&lt;p&gt;I&amp;rsquo;d say that the best memory I have, the one that really solidified the atmosphere in my mind, was seeing a friend from &lt;em&gt;PythonistaCafe&lt;/em&gt; and PyCon talking with someone who was working the venue cleaning up. She was so taken by the friendliness of the conference that she was asking about it and figuring out how she could be a part of it next year. Maybe we&amp;rsquo;ll get to see her in Pittsburgh.&lt;/p&gt;
&lt;p&gt;There was a talk that I had scheduled to go to and just blew the timing and missed. It was &lt;a href=&quot;https://www.youtube.com/watch?v=1kT1VoX7VAs&quot;&gt;Building an Open Source Artificial Pancreas&lt;/a&gt;, and I&amp;rsquo;m still disappointed I didn&amp;rsquo;t make it. It&amp;rsquo;s a great topic and a great talk.&lt;/p&gt;
&lt;h3 id=&quot;geir-arne-hjelle&quot;&gt;Geir Arne Hjelle&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://files.realpython.com/media/gahjelle.470149ee709e.jpg&quot; target=&quot;_blank&quot;&gt;&lt;img class=&quot;img-fluid w-25 rounded-circle float-right ml-3&quot; src=&quot;https://files.realpython.com/media/gahjelle.470149ee709e.jpg&quot; width=&quot;800&quot; height=&quot;800&quot; srcset=&quot;https://robocrop.realpython.net/?url=https%3A//files.realpython.com/media/gahjelle.470149ee709e.jpg&amp;amp;w=200&amp;amp;sig=5f5c996c1ae71bd7f2f89f547a334d508de2f4bb 200w, https://robocrop.realpython.net/?url=https%3A//files.realpython.com/media/gahjelle.470149ee709e.jpg&amp;amp;w=400&amp;amp;sig=0e74ccf912d97528bda85e7b9e9e5064d69a1169 400w, https://files.realpython.com/media/gahjelle.470149ee709e.jpg 800w&quot; sizes=&quot;75vw&quot; alt=&quot;Geir Arne Hjelle&quot;/&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;My name is &lt;a href=&quot;https://realpython.com/team/gahjelle/&quot;&gt;Geir Arne Hjelle&lt;/a&gt;, and I grew up in a small village in the north of Norway. Currently, I live in Oslo where I work with different data science and machine learning projects. Most of the time, I get to use Python and the excellent data science stack built on top of &lt;a href=&quot;https://realpython.com/numpy-array-programming/&quot;&gt;&lt;code&gt;numpy&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I have been writing for &lt;em&gt;Real Python&lt;/em&gt; since the spring of 2018, mostly about general Python packages and concepts. My first article was about the &lt;a href=&quot;https://realpython.com/python-pathlib/&quot;&gt;&lt;code&gt;pathlib&lt;/code&gt; package&lt;/a&gt;, and I&amp;rsquo;m currently working on one about how imports work. In addition, I support other authors by doing reviews of their articles, both outline reviews and technical reviews.&lt;/p&gt;
&lt;p&gt;This year was my first PyCon US. I live in Norway, so I mainly attend conferences in Europe. This fall, I will be at &lt;a href=&quot;https://www.euroscipy.org/2019/&quot;&gt;EuroSciPy&lt;/a&gt; for the fifth time. However, after joining the &lt;em&gt;Real Python&lt;/em&gt; team, I was really tempted by the opportunity to meet some of my new friends and colleagues out in the wild. &lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;#james-mertz&quot;&gt;James&lt;/a&gt; and I managed to meet up last summer, but otherwise I mainly knew the team by their Slack avatars. Meeting and hanging out with the rest of the &lt;em&gt;Real Python&lt;/em&gt; gang, and nerding out over some of the reviews we&amp;rsquo;ve done for each other are great memories I&amp;rsquo;ll treasure for a long time.&lt;/p&gt;
&lt;p&gt;There is so much happening at PyCon. I went all in and stayed for the tutorials, the main conference, and parts of the sprints. I really enjoyed all of it. &lt;/p&gt;
&lt;p&gt;The tutorials were great, including David Beazley&amp;rsquo;s &lt;a href=&quot;https://pyvideo.org/pycon-us-2019/lambda-calculus-from-the-ground-up.html&quot;&gt;deep dive into lambda calculus&lt;/a&gt;. (Yay, math!) I was lucky enough to get to &lt;a href=&quot;https://github.com/gahjelle/talks/tree/master/20190505_pycon_plugins&quot;&gt;give a talk&lt;/a&gt; during the conference, which was a lot of fun. I was very well taken care of before my presentation: I think this is the first time I&amp;rsquo;ve had my own room for preparations, and someone walking me over to the presentation room. &lt;/p&gt;
&lt;p&gt;Afterwards, I got some very nice and interesting questions. During the sprints, I got to help out a little on the new &lt;a href=&quot;https://pypi.org/project/importlib-metadata/&quot;&gt;&lt;code&gt;importlib.metadata&lt;/code&gt;&lt;/a&gt; library Jason Coombs and Barry Warsaw are putting together for Python 3.8. It was great to see first-hand how some of the core developers are working.&lt;/p&gt;
&lt;p&gt;I had so many great experiences in Cleveland that it&amp;rsquo;s hard to think of things I didn&amp;rsquo;t have a chance to do. Although, I&amp;rsquo;ll admit that at this PyCon, I was quite focused on myself (especially with my talk being during the last session of the conference). &lt;/p&gt;
&lt;p&gt;Next time, I&amp;rsquo;ll set aside some time for &lt;a href=&quot;https://realpython.com/pycon-guide/#volunteering-opportunities&quot;&gt;volunteering&lt;/a&gt; and make sure to support the running of the conference more than I did this time around. It was great to see how everybody chipped in: I was welcomed and checked in by Ernest W. Durbin III, who was also the chair of the whole conference.&lt;/p&gt;
&lt;h3 id=&quot;james-mertz&quot;&gt;James Mertz&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://files.realpython.com/media/34794694_10156797037667697_8713056503919017984_n.0b174d713b06.jpg&quot; target=&quot;_blank&quot;&gt;&lt;img class=&quot;img-fluid w-25 rounded-circle float-right ml-3&quot; src=&quot;https://files.realpython.com/media/34794694_10156797037667697_8713056503919017984_n.0b174d713b06.jpg&quot; width=&quot;959&quot; height=&quot;960&quot; srcset=&quot;https://robocrop.realpython.net/?url=https%3A//files.realpython.com/media/34794694_10156797037667697_8713056503919017984_n.0b174d713b06.jpg&amp;amp;w=239&amp;amp;sig=ed56912e9f8820eba641c023b5ce7a68361847e8 239w, https://robocrop.realpython.net/?url=https%3A//files.realpython.com/media/34794694_10156797037667697_8713056503919017984_n.0b174d713b06.jpg&amp;amp;w=479&amp;amp;sig=b33fb80796cac15629ad20809d7bc5800ecbfa05 479w, https://files.realpython.com/media/34794694_10156797037667697_8713056503919017984_n.0b174d713b06.jpg 959w&quot; sizes=&quot;75vw&quot; alt=&quot;James Mertz&quot;/&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m &lt;a href=&quot;https://realpython.com/team/jmertz/&quot;&gt;James Mertz&lt;/a&gt;, and I&amp;rsquo;m a Software Assurance Engineer at NASA&amp;rsquo;s Jet Propulsion Laboratory (JPL).  I&amp;rsquo;m currently working on the Europa Clipper project, which is a satellite that will be orbiting around Jupiter and making very close trips near the moon Europa.  I&amp;rsquo;ve been writing for &lt;em&gt;Real Python&lt;/em&gt; for about a year now with topics ranging from &lt;a href=&quot;https://realpython.com/documenting-python-code/&quot;&gt;documenting Python&lt;/a&gt; to &lt;a href=&quot;https://realpython.com/pycon-guide/&quot;&gt;how to get the most out of PyCon&lt;/a&gt;.  &lt;/p&gt;
&lt;p&gt;This is my fourth year at PyCon, so I&amp;rsquo;m starting to get to know my way around the conference, although each year it&amp;rsquo;s different enough to keep bringing me back.  This year was by far the best for me for two reasons: volunteering and meeting up with the &lt;em&gt;Real Python&lt;/em&gt; gang (both the authors and the readers).&lt;/p&gt;
&lt;p&gt;In my guide on &lt;a href=&quot;https://realpython.com/pycon-guide/&quot;&gt;How to Get the Most Out of PyCon&lt;/a&gt;, I really put a focus on volunteering at PyCon. I realized that, while I had done some things in years past, I hadn&amp;rsquo;t really practiced what I was preaching.  I decided to fully embrace this and tried to help in every way I could.  &lt;/p&gt;
&lt;p&gt;By the end of the conference, I had:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Been a tutorial &amp;ldquo;bouncer&amp;rdquo; for David Beazley&amp;rsquo;s &lt;a href=&quot;https://pyvideo.org/pycon-us-2019/lambda-calculus-from-the-ground-up.html&quot;&gt;deep dive into lambda Calculus&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Helped with registration check-in and even got to check in Michael Kennedy from &lt;em&gt;Python Bytes&lt;/em&gt; and &lt;em&gt;Talk Python to Me&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;Done the swag bag stuffing line dance DJ-ed by Larry Hastings&lt;/li&gt;
&lt;li&gt;Been a session staff runner (the person who makes sure the speaker is in the room on time)&lt;/li&gt;
&lt;li&gt;Been a session staff chair (the person who introduces the speaker)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Through it all, I made some really amazing connections and felt great being able to contribute a little to the community that I love so much.  &lt;/p&gt;
&lt;p&gt;Speaking of community, meeting up with the &lt;em&gt;Real Python&lt;/em&gt; community was another big highlight.  As authors, we really don&amp;rsquo;t get many chances to meet with each other face to face.  Therefore, to finally meet up with some of the people that I&amp;rsquo;ve come to know so well digitally, in the physical world, was a surreal experience.  What made it better was that, even though we were all from different places in the world with different life experiences, we were able to quickly build a team spirit.  &lt;/p&gt;
&lt;p&gt;Perhaps even better than meeting my other &lt;em&gt;Real Python&lt;/em&gt; team members, was meeting you, the readers.  We held our first &lt;em&gt;Real Python&lt;/em&gt; &lt;a href=&quot;https://realpython.com/pycon-guide/#open-spaces&quot;&gt;open space&lt;/a&gt;, where many of you stopped by to chat.  As an author for a digital publisher, it&amp;rsquo;s hard sometimes to connect with the people that you&amp;rsquo;re writing for, but for me, that has become easier.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://files.realpython.com/media/RP-open-space-seated.ef68ec58da7e.jpg&quot; target=&quot;_blank&quot;&gt;&lt;img class=&quot;img-fluid mx-auto d-block &quot; src=&quot;https://files.realpython.com/media/RP-open-space-seated.ef68ec58da7e.jpg&quot; width=&quot;4599&quot; height=&quot;2192&quot; srcset=&quot;https://robocrop.realpython.net/?url=https%3A//files.realpython.com/media/RP-open-space-seated.ef68ec58da7e.jpg&amp;amp;w=1149&amp;amp;sig=c0606a952170dc7506b12bfe9d244bc4dcbdee0d 1149w, https://robocrop.realpython.net/?url=https%3A//files.realpython.com/media/RP-open-space-seated.ef68ec58da7e.jpg&amp;amp;w=2299&amp;amp;sig=ae3a2f29fb001c8c1cf12aec5c33533b0e0c51f3 2299w, https://files.realpython.com/media/RP-open-space-seated.ef68ec58da7e.jpg 4599w&quot; sizes=&quot;75vw&quot; alt=&quot;All attendees of the Real Python Open Space seated at PyCon&quot;/&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This year&amp;rsquo;s PyCon experience was overall fairly balanced as I got to do a lot of networking, seeing talks and tutorials, and even volunteering.  The only thing that I could think that I wish I could&amp;rsquo;ve done was to give a presentation of some sort.  That&amp;rsquo;s what next year is for though.&lt;/p&gt;
&lt;h3 id=&quot;dan-bader&quot;&gt;Dan Bader&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://files.realpython.com/media/daniel-square.d58bf4388750.jpg&quot; target=&quot;_blank&quot;&gt;&lt;img class=&quot;img-fluid w-25 rounded-circle float-right ml-3&quot; src=&quot;https://files.realpython.com/media/daniel-square.d58bf4388750.jpg&quot; width=&quot;1000&quot; height=&quot;1000&quot; srcset=&quot;https://robocrop.realpython.net/?url=https%3A//files.realpython.com/media/daniel-square.d58bf4388750.jpg&amp;amp;w=250&amp;amp;sig=0f6c5ef7f5786b2a198fe2d700695467601836fe 250w, https://robocrop.realpython.net/?url=https%3A//files.realpython.com/media/daniel-square.d58bf4388750.jpg&amp;amp;w=500&amp;amp;sig=6d44e31ac8b0ed5d7bf09163b66e9374d79b7256 500w, https://files.realpython.com/media/daniel-square.d58bf4388750.jpg 1000w&quot; sizes=&quot;75vw&quot; alt=&quot;Dan Bader&quot;/&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Hey I&amp;rsquo;m &lt;a href=&quot;https://realpython.com/team/dbader/&quot;&gt;Dan Bader&lt;/a&gt;, and I&amp;rsquo;m the owner and editor-in-chief here at &lt;em&gt;Real Python&lt;/em&gt;. I also do all of the back-end and front-end development for the Django-based CMS and other infrastructure that &lt;code&gt;realpython.com&lt;/code&gt; runs on. &lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m a long-time Pythonista and super passionate about teaching Python. Publishing my own &lt;a href=&quot;https://realpython.com/products/python-tricks-book/&quot;&gt;Python programming book&lt;/a&gt; was a lifelong dream and getting to run &lt;em&gt;Real Python&lt;/em&gt; together with an awesome team now is the icing on the cake!&lt;/p&gt;
&lt;p&gt;This year was my fifth PyCon, and it won&amp;rsquo;t be the last, that&amp;rsquo;s for sure&amp;hellip;&lt;/p&gt;
&lt;p&gt;My personal highlights were hanging out with the &lt;em&gt;Real Python&lt;/em&gt; tutorial team and meeting many of them in person for the first time. That just made my heart jump! We went out for food and drinks a couple of nights, and one random memory that I&amp;rsquo;ll probably never forget is finding out how much &lt;a href=&quot;https://realpython.com/team/ljones/&quot;&gt;Logan&lt;/a&gt; loves the &lt;a href=&quot;https://en.wikipedia.org/wiki/The_Golden_Girls&quot;&gt;Golden Girls TV show&lt;/a&gt; : - D&lt;/p&gt;
&lt;p&gt;During the day, the nice folks at &lt;a href=&quot;https://blog.jetbrains.com/pycharm/2019/04/pycharm-hosts-python-creators-at-expanded-pycon-booth/&quot;&gt;JetBrains gave us some space at their PyCharm booth&lt;/a&gt;, so we all got to wear our &lt;em&gt;Real Python&lt;/em&gt; swag and chat with readers as well as hand out stickers and pins. That was super fun!&lt;/p&gt;
&lt;p&gt;Another great memory is the &lt;em&gt;Real Python&lt;/em&gt; open space we organized where several dozen readers and members showed up to say &amp;ldquo;hi.&amp;rdquo; That just blew my mind and was one of my favorite PyCon experiences so far! &lt;/p&gt;
&lt;p&gt;I felt pretty burned out when I first arrived at PyCon after working non-stop for a couple of months on the launch of our &lt;a href=&quot;https://realpython.com/account/join/&quot;&gt;video subscriptions feature&lt;/a&gt;, and seeing this massive turnout felt amazing. I didn&amp;rsquo;t really know what to say at first! Thanks everybody for stopping by :)&lt;/p&gt;
&lt;p&gt;This year was also the second time we hosted an open-space meetup for the &lt;a href=&quot;https://www.pythonistacafe.com&quot;&gt;&lt;em&gt;PythonistaCafe&lt;/em&gt; forum&lt;/a&gt;, and it was super cool to see how this wacky little project has sparked such a tightly knit and awesome community now.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://files.realpython.com/media/realpython-pycon-open-space.4bfa6567a567.jpg&quot; target=&quot;_blank&quot;&gt;&lt;img class=&quot;img-fluid mx-auto d-block &quot; src=&quot;https://files.realpython.com/media/realpython-pycon-open-space.4bfa6567a567.jpg&quot; width=&quot;1920&quot; height=&quot;1080&quot; srcset=&quot;https://robocrop.realpython.net/?url=https%3A//files.realpython.com/media/realpython-pycon-open-space.4bfa6567a567.jpg&amp;amp;w=480&amp;amp;sig=d243629404fc41a7c01336e3a374dffbfa5b924d 480w, https://robocrop.realpython.net/?url=https%3A//files.realpython.com/media/realpython-pycon-open-space.4bfa6567a567.jpg&amp;amp;w=960&amp;amp;sig=81a6c5c7c5b2989e633fda8b7e8ec00538bd7908 960w, https://files.realpython.com/media/realpython-pycon-open-space.4bfa6567a567.jpg 1920w&quot; sizes=&quot;75vw&quot; alt=&quot;All attendees of the Real Python Open Space at PyCon&quot;/&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Another highlight was recording a live episode of the &lt;a href=&quot;https://talkpython.fm/episodes/show/215/the-software-powering-talk-python-courses-and-podcast&quot;&gt;&lt;em&gt;Talk Python&lt;/em&gt; podcast together with Mike Kennedy&lt;/a&gt;. Always a treat hanging out with this guy :)&lt;/p&gt;
&lt;p&gt;I wish I would&amp;rsquo;ve had more time to go to talks. I was super impressed with the talks that &lt;a href=&quot;https://www.youtube.com/watch?v=98s9YfoXB68&quot;&gt;Geir Arne&lt;/a&gt; and &lt;a href=&quot;https://www.youtube.com/watch?v=dqdsNoApJ80&quot;&gt;Anthony&lt;/a&gt; from the &lt;em&gt;Real Python&lt;/em&gt; Tutorial Team gave. Be sure to check out the recordings when you have the chance.&lt;/p&gt;
&lt;p&gt;Happy Pythoning, and see you next year!&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;/h2&gt;
&lt;p&gt;&lt;img class=&quot;img-fluid ml-3 float-right w-25&quot; src=&quot;https://files.realpython.com/media/ricky-pycon-2019.f85510809f7d.jpg&quot; width=&quot;1943&quot; height=&quot;2699&quot; srcset=&quot;https://robocrop.realpython.net/?url=https%3A//files.realpython.com/media/ricky-pycon-2019.f85510809f7d.jpg&amp;amp;w=485&amp;amp;sig=c9d705107886c223d272da71fa11e7e704ed6aed 485w, https://robocrop.realpython.net/?url=https%3A//files.realpython.com/media/ricky-pycon-2019.f85510809f7d.jpg&amp;amp;w=971&amp;amp;sig=0671a59b03b8e1ad5cb137dc22758fcc0b04d1d9 971w, https://files.realpython.com/media/ricky-pycon-2019.f85510809f7d.jpg 1943w&quot; sizes=&quot;75vw&quot; alt=&quot;Ricky White holding a Python themed staff&quot;/&gt;&lt;/p&gt;
&lt;p&gt;Regardless of the location, a PyCon is a joyous experience. Whether you are meeting colleagues, online friends, or strangers who share a passion other than Python, it&amp;rsquo;s the people that make the experience special. The old saying, &amp;ldquo;came for the language, but stayed for the community&amp;rdquo; never rings more true than at PyCon US.&lt;/p&gt;
&lt;p&gt;No two Pythonistas are the same, and there is something for everyone in the diversity of the events, talks, and tutorials taking place. Personally, I&amp;rsquo;m looking forward to next year&amp;rsquo;s PyCon already. Schedule permitting, I&amp;rsquo;ll make every effort to join the sprints in 2020. But even if I don&amp;rsquo;t get to tick that off my list, I already know that next year I&amp;rsquo;ll be excited to meet you and many others in spite of my introversion. &lt;/p&gt;
&lt;p&gt;If you were at PyCon US and came to say &amp;ldquo;hi,&amp;rdquo; or joined us for the &lt;em&gt;Real Python&lt;/em&gt; or &lt;em&gt;PythonistaCafe&lt;/em&gt; open spaces, then leave a comment below and let us know what your favorite part of PyCon was. What&amp;rsquo;s your one tip you would give someone who will be attending any PyCon for the first time next year? Happy coding!&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>Build a Recommendation Engine With Collaborative Filtering</title>
      <id>https://realpython.com/build-recommendation-engine-collaborative-filtering/</id>
      <link href="https://realpython.com/build-recommendation-engine-collaborative-filtering/"/>
      <updated>2019-07-10T14:00:00+00:00</updated>
      <summary>In this tutorial, you&#39;ll learn about collaborative filtering, which is one of the most common approaches for building recommender systems. You&#39;ll cover the various types of algorithms that fall under this category and see how to implement them in Python.</summary>
      <content type="html">
        &lt;p&gt;Collaborative Filtering is the most common technique used when it comes to building intelligent recommender systems that can learn to give better recommendations as more information about users is collected.&lt;/p&gt;
&lt;p&gt;Most websites like Amazon, YouTube, and Netflix use collaborative filtering as a part of their sophisticated recommendation systems. You can use this technique to build recommenders that give suggestions to a user on the basis of the likes and dislikes of similar users.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;In this article, you&amp;rsquo;ll learn about:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Collaborative filtering and it types&lt;/li&gt;
&lt;li&gt;Data needed to build a recommender&lt;/li&gt;
&lt;li&gt;Libraries available in Python to build recommenders&lt;/li&gt;
&lt;li&gt;Use cases and challenges of collaborative filtering&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-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;what-is-collaborative-filtering&quot;&gt;What Is Collaborative Filtering?&lt;/h2&gt;
&lt;p&gt;Collaborative filtering is a technique that can filter out items that a user might like on the basis of reactions by similar users.&lt;/p&gt;
&lt;p&gt;It works by searching a large group of people and finding a smaller set of users with tastes similar to a particular user. It looks at the items they like and combines them to create a ranked list of suggestions.&lt;/p&gt;
&lt;p&gt;There are many ways to decide which users are similar and combine their choices to create a list of recommendations. This article will show you how to do that with Python.&lt;/p&gt;
&lt;h2 id=&quot;the-dataset&quot;&gt;The Dataset&lt;/h2&gt;
&lt;p&gt;To experiment with recommendation algorithms, you&amp;rsquo;ll need data that contains a &lt;strong&gt;set of items&lt;/strong&gt; and a &lt;strong&gt;set of users&lt;/strong&gt; who have reacted to some of the items.&lt;/p&gt;
&lt;p&gt;The reaction can be &lt;strong&gt;explicit&lt;/strong&gt; (rating on a scale of 1 to 5, likes or dislikes) or &lt;strong&gt;implicit&lt;/strong&gt; (viewing an item, adding it to a wish list, the time spent on an article).&lt;/p&gt;
&lt;p&gt;While working with such data, you&amp;rsquo;ll mostly see it in the form of a &lt;strong&gt;matrix&lt;/strong&gt; consisting of the reactions given by a set of users to some items from a set of items. Each row would contain the ratings given by a user, and each column would contain the ratings received by an item. A matrix with five users and five items could look like this:&lt;/p&gt;
&lt;figure class=&quot;figure mx-auto d-block&quot;&gt;&lt;a href=&quot;https://files.realpython.com/media/rating-matrix.04153775e4c1.jpg&quot; target=&quot;_blank&quot;&gt;&lt;img class=&quot;img-fluid mx-auto d-block w-33&quot; src=&quot;https://files.realpython.com/media/rating-matrix.04153775e4c1.jpg&quot; width=&quot;477&quot; height=&quot;428&quot; srcset=&quot;https://robocrop.realpython.net/?url=https%3A//files.realpython.com/media/rating-matrix.04153775e4c1.jpg&amp;amp;w=119&amp;amp;sig=7f60cc35b5e6665a4dda4b288bb843721480728b 119w, https://robocrop.realpython.net/?url=https%3A//files.realpython.com/media/rating-matrix.04153775e4c1.jpg&amp;amp;w=238&amp;amp;sig=83574add3cb0540d7698921198d6563efa01cbc5 238w, https://files.realpython.com/media/rating-matrix.04153775e4c1.jpg 477w&quot; sizes=&quot;75vw&quot; alt=&quot;User Item Rating matrix used in recommender systems&quot;/&gt;&lt;/a&gt;&lt;figcaption class=&quot;figure-caption text-center&quot;&gt;Rating Matrix&lt;/figcaption&gt;&lt;/figure&gt;

&lt;p&gt;The matrix shows five users who have rated some of the items on a scale of 1 to 5. For example, the first user has given a rating 4 to the third item.&lt;/p&gt;
&lt;p&gt;In most cases, the cells in the matrix are empty, as users only rate a few items. It&amp;rsquo;s highly unlikely for every user to rate or react to every item available. A matrix with mostly empty cells is called &lt;strong&gt;sparse&lt;/strong&gt;, and the opposite to that (a mostly filled matrix) is called &lt;strong&gt;dense&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;There are a lot of datasets that have been collected and made available to the public for research and benchmarking. Here&amp;rsquo;s a &lt;a href=&quot;https://github.com/caserec/Datasets-for-Recommneder-Systems&quot;&gt;list of high-quality data sources&lt;/a&gt; that you can choose from.&lt;/p&gt;
&lt;p&gt;The best one to get started would be the &lt;a href=&quot;https://grouplens.org/datasets/movielens/&quot;&gt;MovieLens&lt;/a&gt; dataset collected by GroupLens Research. In particular, the &lt;a href=&quot;https://grouplens.org/datasets/movielens/100k/&quot;&gt;MovieLens 100k dataset&lt;/a&gt; is a stable benchmark dataset with 100,000 ratings given by 943 users for 1682 movies, with each user having rated at least 20 movies.&lt;/p&gt;
&lt;p&gt;This dataset consists of many files that contain information about the movies, the users, and the ratings given by users to the movies they have watched. The ones that are of interest are the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;u.item&lt;/code&gt;:&lt;/strong&gt; the list of movies&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;u.data&lt;/code&gt;:&lt;/strong&gt; the list of ratings given by users&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The file &lt;code&gt;u.data&lt;/code&gt; that contains the ratings is a tab separated list of user ID, item ID, rating, and timestamp. The first few lines of the file look like this:&lt;/p&gt;
&lt;figure class=&quot;figure mx-auto d-block&quot;&gt;&lt;a href=&quot;https://files.realpython.com/media/movielens-head.0542b4c067c7.jpg&quot; target=&quot;_blank&quot;&gt;&lt;img class=&quot;img-fluid mx-auto d-block w-50&quot; src=&quot;https://files.realpython.com/media/movielens-head.0542b4c067c7.jpg&quot; width=&quot;707&quot; height=&quot;434&quot; srcset=&quot;https://robocrop.realpython.net/?url=https%3A//files.realpython.com/media/movielens-head.0542b4c067c7.jpg&amp;amp;w=176&amp;amp;sig=e50360fb87c055aabc11f0766e6098fe2e571846 176w, https://robocrop.realpython.net/?url=https%3A//files.realpython.com/media/movielens-head.0542b4c067c7.jpg&amp;amp;w=353&amp;amp;sig=6ccdd2c850d3a913e78ef8b8424f254cfa8ca9c8 353w, https://files.realpython.com/media/movielens-head.0542b4c067c7.jpg 707w&quot; sizes=&quot;75vw&quot; alt=&quot;The first five rows of the movielens 100k dataset&quot;/&gt;&lt;/a&gt;&lt;figcaption class=&quot;figure-caption text-center&quot;&gt;First 5 Rows of MovieLens 100k Data&lt;/figcaption&gt;&lt;/figure&gt;

&lt;p&gt;As shown above, the file tells what rating a user gave to a particular movie. This file contains 100,000 such ratings, which will be used to predict the ratings of the movies not seen by the users.&lt;/p&gt;
&lt;h2 id=&quot;steps-involved-in-collaborative-filtering&quot;&gt;Steps Involved in Collaborative Filtering&lt;/h2&gt;
&lt;p&gt;To build a system that can automatically recommend items to users based on the preferences of other users, the first step is to find similar users or items. The second step is to predict the ratings of the items that are not yet rated by a user. So, you will need the answers to these questions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;How do you determine which users or items are similar to one another?&lt;/li&gt;
&lt;li&gt;Given that you know which users are similar, how do you determine the rating that a user would give to an item based on the ratings of similar users?&lt;/li&gt;
&lt;li&gt;How do you measure the accuracy of the ratings you calculate?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The first two questions don&amp;rsquo;t have single answers. Collaborative filtering is a family of algorithms where there are multiple ways to find similar users or items and multiple ways to calculate rating based on ratings of similar users. Depending on the choices you make, you end up with a type of collaborative filtering approach. You&amp;rsquo;ll get to see the various approaches to find similarity and predict ratings in this article.&lt;/p&gt;
&lt;p&gt;One important thing to keep in mind is that in an approach based purely on collaborative filtering, the similarity is not calculated using factors like the age of users, genre of the movie, or any other data about users or items. It is calculated only on the basis of the rating (explicit or implicit) a user gives to an item. For example, two users can be considered similar if they give the same ratings to ten movies despite there being a big difference in their age.&lt;/p&gt;
&lt;p&gt;The third question for how to measure the accuracy of your predictions also has multiple answers, which include error calculation techniques that can be used in many places and not just recommenders based on collaborative filtering.&lt;/p&gt;
&lt;p&gt;One of the approaches to measure the accuracy of your result is the Root Mean Square Error (RMSE), in which you predict ratings for a test dataset of user-item pairs whose rating values are already known. The difference between the known value and the predicted value would be the error. Square all the error values for the test set, find the average (or mean), and then take the square root of that average to get the RMSE.&lt;/p&gt;
&lt;p&gt;Another metric to measure the accuracy is Mean Absolute Error (MAE), in which you find the magnitude of error by finding its absolute value and then taking the average of all error values.&lt;/p&gt;
&lt;p&gt;You don&amp;rsquo;t need to worry about the details of RMSE or MAE at this point as they are readily available as part of various packages in Python, and you will see them later in the article.&lt;/p&gt;
&lt;p&gt;Now let&amp;rsquo;s look at the different types of algorithms in the family of collaborative filtering.&lt;/p&gt;
&lt;h2 id=&quot;memory-based&quot;&gt;Memory Based&lt;/h2&gt;
&lt;p&gt;The first category includes algorithms that are memory based, in which statistical techniques are applied to the entire dataset to calculate the predictions.&lt;/p&gt;
&lt;p&gt;To find the rating &lt;strong&gt;R&lt;/strong&gt; that a user &lt;strong&gt;U&lt;/strong&gt; would give to an item &lt;strong&gt;I&lt;/strong&gt;, the approach includes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Finding users similar to &lt;strong&gt;U&lt;/strong&gt; who have rated the item &lt;strong&gt;I&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Calculating the rating &lt;strong&gt;R&lt;/strong&gt; based the ratings of users found in the previous step&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You&amp;rsquo;ll see each of them in detail in the following sections. &lt;/p&gt;
&lt;h3 id=&quot;how-to-find-similar-users-on-the-basis-of-ratings&quot;&gt;How to Find Similar Users on the Basis of Ratings&lt;/h3&gt;
&lt;p&gt;To understand the concept of similarity, let&amp;rsquo;s create a simple dataset first.&lt;/p&gt;
&lt;p&gt;The data includes four users &lt;strong&gt;A&lt;/strong&gt;, &lt;strong&gt;B&lt;/strong&gt;, &lt;strong&gt;C&lt;/strong&gt;, and &lt;strong&gt;D&lt;/strong&gt;, who have rated two movies. The ratings are stored in lists, and each list contains two numbers indicating the rating of each movie:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Ratings by &lt;strong&gt;A&lt;/strong&gt; are &lt;code&gt;[1.0, 2.0]&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Ratings by &lt;strong&gt;B&lt;/strong&gt; are &lt;code&gt;[2.0, 4.0]&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Ratings by &lt;strong&gt;C&lt;/strong&gt; are &lt;code&gt;[2.5, 4.0]&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Ratings by &lt;strong&gt;D&lt;/strong&gt; are &lt;code&gt;[4.5, 5.0]&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To start off with a visual clue, plot the ratings of two movies given by the users on a graph and look for a pattern. The graph looks like this:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://files.realpython.com/media/euclidean-distance.74e8c9d0be22.jpg&quot; target=&quot;_blank&quot;&gt;&lt;img class=&quot;img-fluid mx-auto d-block border w-66&quot; src=&quot;https://files.realpython.com/media/euclidean-distance.74e8c9d0be22.jpg&quot; width=&quot;651&quot; height=&quot;428&quot; srcset=&quot;https://robocrop.realpython.net/?url=https%3A//files.realpython.com/media/euclidean-distance.74e8c9d0be22.jpg&amp;amp;w=162&amp;amp;sig=b6160b69d41d021e221557e2c09b0d4c75ae37ec 162w, https://robocrop.realpython.net/?url=https%3A//files.realpython.com/media/euclidean-distance.74e8c9d0be22.jpg&amp;amp;w=325&amp;amp;sig=44c4f1babe14d45634b59f2da9142b0c1ebdda85 325w, https://files.realpython.com/media/euclidean-distance.74e8c9d0be22.jpg 651w&quot; sizes=&quot;75vw&quot; alt=&quot;Points plotted on a graph for visualizing Euclidean distance&quot;/&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;In the graph above, each point represents a user and is plotted against the ratings they gave to two movies.&lt;/p&gt;
&lt;p&gt;Looking at the distance between the points seems to be a good way to estimate similarity, right? You can find the distance using the formula for Euclidean distance between two points. You can use the function available in &lt;code&gt;scipy&lt;/code&gt; as shown in the following program:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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;scipy&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;spatial&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;a&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;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;n&quot;&gt;b&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;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;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c&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;mf&quot;&gt;2.5&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;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;d&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;mf&quot;&gt;4.5&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;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;spatial&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;distance&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;euclidean&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;2.5&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;spatial&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;distance&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;euclidean&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;0.5&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;spatial&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;distance&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;euclidean&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;2.23606797749979&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;As shown above, you can use &lt;code&gt;scipy.spatial.distance.euclidean&lt;/code&gt; to calculate the distance between two points. Using it to calculate the distance between the ratings of &lt;strong&gt;A&lt;/strong&gt;, &lt;strong&gt;B&lt;/strong&gt;, and &lt;strong&gt;D&lt;/strong&gt; to that of &lt;strong&gt;C&lt;/strong&gt; shows us that in terms of distance, the ratings of &lt;strong&gt;C&lt;/strong&gt; are closest to those of &lt;strong&gt;B&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;You can see that user &lt;strong&gt;C&lt;/strong&gt; is closest to &lt;strong&gt;B&lt;/strong&gt; even by looking at the graph. But out of &lt;strong&gt;A&lt;/strong&gt; and &lt;strong&gt;D&lt;/strong&gt; only, who is &lt;strong&gt;C&lt;/strong&gt; closer to?&lt;/p&gt;
&lt;p&gt;You could say &lt;strong&gt;C&lt;/strong&gt; is closer to &lt;strong&gt;D&lt;/strong&gt; in terms of distance. But looking at the rankings, it would seem that the choices of &lt;strong&gt;C&lt;/strong&gt; would align with that of &lt;strong&gt;A&lt;/strong&gt; more than &lt;strong&gt;D&lt;/strong&gt; because both &lt;strong&gt;A&lt;/strong&gt; and &lt;strong&gt;C&lt;/strong&gt; like the second movie almost twice as much as they like the first movie, but &lt;strong&gt;D&lt;/strong&gt; likes both of the movies equally.&lt;/p&gt;
&lt;p&gt;So, what can you use to identify such patterns that Euclidean distance cannot? Can the angle between the lines joining the points to the origin be used to make a decision? You can take a look at the angle between the lines joining the origin of the graph to the respective points as shown:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://files.realpython.com/media/cosine-similarity.76bcd5413eb8.jpg&quot; target=&quot;_blank&quot;&gt;&lt;img class=&quot;img-fluid mx-auto d-block border w-66&quot; src=&quot;https://files.realpython.com/media/cosine-similarity.76bcd5413eb8.jpg&quot; width=&quot;639&quot; height=&quot;428&quot; srcset=&quot;https://robocrop.realpython.net/?url=https%3A//files.realpython.com/media/cosine-similarity.76bcd5413eb8.jpg&amp;amp;w=159&amp;amp;sig=cb48f947ee50eacd5f5627ae17645311b394abae 159w, https://robocrop.realpython.net/?url=https%3A//files.realpython.com/media/cosine-similarity.76bcd5413eb8.jpg&amp;amp;w=319&amp;amp;sig=fd1c32d688142298b5d182950c6e7570e2e1ed9f 319w, https://files.realpython.com/media/cosine-similarity.76bcd5413eb8.jpg 639w&quot; sizes=&quot;75vw&quot; alt=&quot;Two dimensional vectors plotted on a graph to explain angle as a distance metric&quot;/&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The graph shows four lines joining each point to the origin. The lines for &lt;strong&gt;A&lt;/strong&gt; and &lt;strong&gt;B&lt;/strong&gt; are coincident, making the angle between them zero.&lt;/p&gt;
&lt;p&gt;You can consider that, if the angle between the lines is increased, then the similarity decreases, and if the angle is zero, then the users are very similar.&lt;/p&gt;
&lt;p&gt;To calculate similarity using angle, you need a function that returns a &lt;strong&gt;higher similarity&lt;/strong&gt; or &lt;strong&gt;smaller distance&lt;/strong&gt; for a lower angle and a &lt;strong&gt;lower similarity&lt;/strong&gt; or &lt;strong&gt;larger distance&lt;/strong&gt; for a higher angle. The cosine of an angle is a function that decreases from 1 to -1 as the angle increases from 0 to 180.&lt;/p&gt;
&lt;p&gt;You can use the cosine of the angle to find the similarity between two users. The higher the angle, the lower will be the cosine and thus, the lower will be the similarity of the users. You can also inverse the value of the cosine of the angle to get the cosine distance between the users by subtracting it from 1.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;scipy&lt;/code&gt; has a function that calculates the &lt;strong&gt;cosine distance&lt;/strong&gt; of vectors. It returns a higher value for higher angle:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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;scipy&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;spatial&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;a&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;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;n&quot;&gt;b&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;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;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c&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;mf&quot;&gt;2.5&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;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;d&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;mf&quot;&gt;4.5&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;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;spatial&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;distance&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cosine&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;0.004504527406047898&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;spatial&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;distance&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cosine&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;0.004504527406047898&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;spatial&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;distance&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cosine&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;0.015137225946083022&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;spatial&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;distance&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cosine&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;0.0&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The lower angle between the vectors of &lt;strong&gt;C&lt;/strong&gt; and &lt;strong&gt;A&lt;/strong&gt; gives a lower cosine distance value. If you want to rank user similarities in this way, use cosine distance.&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; In the above example, only two movies are considered, which makes it easier to visualize the rating vectors in two dimensions. This is only done to make the explanation easier. &lt;/p&gt;
&lt;p&gt;Real use cases with multiple items would involve more dimensions in rating vectors. You might want to go into the mathematics of &lt;a href=&quot;https://en.wikipedia.org/wiki/Cosine_similarity&quot;&gt;cosine similarity&lt;/a&gt; as well.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;Notice that users &lt;strong&gt;A&lt;/strong&gt; and &lt;strong&gt;B&lt;/strong&gt; are considered absolutely similar in the cosine similarity metric despite having different ratings. This is actually a common occurrence in the real world, and the users like the user &lt;strong&gt;A&lt;/strong&gt; are what you can call &lt;strong&gt;tough raters&lt;/strong&gt;. An example would be a movie critic who always gives out ratings lower than the average, but the rankings of the items in their list would be similar to the &lt;strong&gt;Average raters&lt;/strong&gt; like &lt;strong&gt;B&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;To factor in such individual user preferences, you will need to bring all users to the same level by removing their biases. You can do this by subtracting the average rating given by that user to all items from each item rated by that user. Here&amp;rsquo;s what it would look like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;For user &lt;strong&gt;A&lt;/strong&gt;, the rating vector &lt;code&gt;[1, 2]&lt;/code&gt; has the average &lt;code&gt;1.5&lt;/code&gt;. Subtracting &lt;code&gt;1.5&lt;/code&gt; from every rating would give you the vector &lt;code&gt;[-0.5, 0.5]&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;For user &lt;strong&gt;B&lt;/strong&gt;, the rating vector &lt;code&gt;[2, 4]&lt;/code&gt; has the average &lt;code&gt;3&lt;/code&gt;. Subtracting &lt;code&gt;3&lt;/code&gt; from every rating would give you the vector &lt;code&gt;[-1, 1]&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;By doing this, you have changed the value of the average rating given by every user to 0. Try doing the same for users &lt;strong&gt;C&lt;/strong&gt; and &lt;strong&gt;D&lt;/strong&gt;, and you&amp;rsquo;ll see that the ratings are now adjusted to give an average of 0 for all users, which brings them all to the same level and removes their biases.&lt;/p&gt;
&lt;p&gt;The cosine of the angle between the adjusted vectors is called &lt;strong&gt;centered cosine&lt;/strong&gt;. This approach is normally used when there are a lot of missing values in the vectors, and you need to place a common value to fill up the missing values.&lt;/p&gt;
&lt;p&gt;Filling up the missing values in the ratings matrix with a random value could result in inaccuracies. A good choice to fill the missing values could be the average rating of each user, but the original averages of user &lt;strong&gt;A&lt;/strong&gt; and &lt;strong&gt;B&lt;/strong&gt; are &lt;code&gt;1.5&lt;/code&gt; and &lt;code&gt;3&lt;/code&gt; respectively, and filling up all the empty values of &lt;strong&gt;A&lt;/strong&gt; with &lt;code&gt;1.5&lt;/code&gt; and those of &lt;strong&gt;B&lt;/strong&gt; with &lt;code&gt;3&lt;/code&gt; would make them dissimilar users.&lt;/p&gt;
&lt;p&gt;But after adjusting the values, the &lt;strong&gt;centered&lt;/strong&gt; average of both users is &lt;code&gt;0&lt;/code&gt;, which allows you to capture the idea of the item being above or below average more accurately for both users with all missing values in both user&amp;rsquo;s vectors having the same value &lt;code&gt;0&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Euclidean distance and cosine similarity are some of the approaches that you can use to find users similar to one another and even items similar to one another. (The function used above calculates cosine distance. To calculate cosine similarity, subtract the distance from 1.)&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 formula for centered cosine is the same as that for Pearson correlation coefficient. You will find that many resources and libraries on recommenders refer to the implementation of centered cosine as Pearson Correlation.&lt;/p&gt;
&lt;/div&gt;
&lt;h3 id=&quot;how-to-calculate-the-ratings&quot;&gt;How to Calculate the Ratings&lt;/h3&gt;
&lt;p&gt;After you have determined a list of users similar to a user &lt;strong&gt;U&lt;/strong&gt;, you need to calculate the rating &lt;strong&gt;R&lt;/strong&gt; that &lt;strong&gt;U&lt;/strong&gt; would give to a certain item &lt;strong&gt;I&lt;/strong&gt;. Again, just like similarity, you can do this in multiple ways.&lt;/p&gt;
&lt;p&gt;You can predict that a user&amp;rsquo;s rating &lt;strong&gt;R&lt;/strong&gt; for an item &lt;strong&gt;I&lt;/strong&gt; will be close to the average of the ratings given to &lt;strong&gt;I&lt;/strong&gt; by the top 5 or top 10 users most similar to &lt;strong&gt;U&lt;/strong&gt;. The mathematical formula for the average rating given by &lt;em&gt;n&lt;/em&gt; users would look like this:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://files.realpython.com/media/average_rating.73cdfc1d58c4.png&quot; target=&quot;_blank&quot;&gt;&lt;img class=&quot;img-fluid mx-auto d-block w-33&quot; src=&quot;https://files.realpython.com/media/average_rating.73cdfc1d58c4.png&quot; width=&quot;624&quot; height=&quot;228&quot; srcset=&quot;https://robocrop.realpython.net/?url=https%3A//files.realpython.com/media/average_rating.73cdfc1d58c4.png&amp;amp;w=156&amp;amp;sig=cf8ebf0f174949cacbb2ed26e63bbe9a8c3d0f57 156w, https://robocrop.realpython.net/?url=https%3A//files.realpython.com/media/average_rating.73cdfc1d58c4.png&amp;amp;w=312&amp;amp;sig=c9201a7d0c2f3ba7ae843fe457c796e41a6ad255 312w, https://files.realpython.com/media/average_rating.73cdfc1d58c4.png 624w&quot; sizes=&quot;75vw&quot; alt=&quot;Formula for average rating&quot;/&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This formula shows that the average rating given by the &lt;em&gt;n&lt;/em&gt; similar users is equal to the sum of the ratings given by them divided by the number of similar users, which is &lt;em&gt;n&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;There will be situations where the &lt;em&gt;n&lt;/em&gt; similar users that you found are not equally similar to the target user &lt;strong&gt;U&lt;/strong&gt;. The top 3 of them might be very similar, and the rest might not be as similar to &lt;strong&gt;U&lt;/strong&gt; as the top 3. In that case, you could consider an approach where the rating of the most similar user matters more than the second most similar user and so on. The weighted average can help us achieve that.&lt;/p&gt;
&lt;p&gt;In the weighted average approach, you multiply each rating by a similarity factor(which tells how similar the users are). By multiplying with the similarity factor, you add weights to the ratings. The heavier the weight, the more the rating would matter. &lt;/p&gt;
&lt;p&gt;The similarity factor, which would act as weights, should be the inverse of the distance discussed above because less distance implies higher similarity. For example, you can subtract the cosine distance from 1 to get cosine similarity.&lt;/p&gt;
&lt;p&gt;With the similarity factor &lt;strong&gt;S&lt;/strong&gt; for each user similar to the target user &lt;strong&gt;U&lt;/strong&gt;, you can calculate the weighted average using this formula:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://files.realpython.com/media/weighted_rating.06ba3ea506b6.png&quot; target=&quot;_blank&quot;&gt;&lt;img class=&quot;img-fluid mx-auto d-block w-50&quot; src=&quot;https://files.realpython.com/media/weighted_rating.06ba3ea506b6.png&quot; width=&quot;1037&quot; height=&quot;228&quot; srcset=&quot;https://robocrop.realpython.net/?url=https%3A//files.realpython.com/media/weighted_rating.06ba3ea506b6.png&amp;amp;w=259&amp;amp;sig=ab3b539ba8d49919c91410cd700c9ded7847794f 259w, https://robocrop.realpython.net/?url=https%3A//files.realpython.com/media/weighted_rating.06ba3ea506b6.png&amp;amp;w=518&amp;amp;sig=529a3675d01cc44388365b811f9f54c4c3ec0bec 518w, https://files.realpython.com/media/weighted_rating.06ba3ea506b6.png 1037w&quot; sizes=&quot;75vw&quot; alt=&quot;Formula for weighted average rating&quot;/&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;In the above formula, every rating is multiplied by the similarity factor of the user who gave the rating. The final predicted rating by user &lt;strong&gt;U&lt;/strong&gt; will be equal to the sum of the weighted ratings divided by the sum of the weights.&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; In case you&amp;rsquo;re wondering why the sum of weighted ratings is being divided by the sum of the weights and not by &lt;em&gt;n&lt;/em&gt;, consider this: in the previous formula of the average, where you divided by &lt;em&gt;n&lt;/em&gt;, the value of the weight was 1.&lt;/p&gt;
&lt;p&gt;The denominator is always the sum of weights when it comes to finding averages, and in the case of the normal average, the weight being 1 means the denominator would be equal to &lt;em&gt;n&lt;/em&gt;. &lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;With a weighted average, you give more consideration to the ratings of similar users in order of their similarity.&lt;/p&gt;
&lt;p&gt;Now, you know how to find similar users and how to calculate ratings based on their ratings. There&amp;rsquo;s also a variation of collaborative filtering where you predict ratings by finding items similar to each other instead of users and calculating the ratings. You&amp;rsquo;ll read about this variation in the next section.&lt;/p&gt;
&lt;h3 id=&quot;user-based-vs-item-based-collaborative-filtering&quot;&gt;User-Based vs Item-Based Collaborative Filtering&lt;/h3&gt;
&lt;p&gt;The technique in the examples explained above, where the rating matrix is used to find similar users based on the ratings they give, is called user-based or user-user collaborative filtering. If you use the rating matrix to find similar items based on the ratings given to them by users, then the approach is called item-based or item-item collaborative filtering.&lt;/p&gt;
&lt;p&gt;The two approaches are mathematically quite similar, but there is a conceptual difference between the two. Here&amp;rsquo;s how the two compare:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;User-based:&lt;/strong&gt; For a user &lt;strong&gt;U&lt;/strong&gt;, with a set of similar users determined based on rating vectors consisting of given item ratings, the rating for an item &lt;strong&gt;I&lt;/strong&gt;, which hasn&amp;rsquo;t been rated, is found by picking out N users from the similarity list who have rated the item &lt;strong&gt;I&lt;/strong&gt; and calculating the rating based on these N ratings.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Item-based:&lt;/strong&gt; For an item &lt;strong&gt;I&lt;/strong&gt;, with a set of similar items determined based on rating vectors consisting of received user ratings, the rating by a user &lt;strong&gt;U&lt;/strong&gt;, who hasn&amp;rsquo;t rated it, is found by picking out N items from the similarity list that have been rated by &lt;strong&gt;U&lt;/strong&gt; and calculating the rating based on these N ratings.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Item-based collaborative filtering was developed by Amazon. In a system where there are more users than items, item-based filtering is faster and more stable than user-based. It is effective because usually, the average rating received by an item doesn&amp;rsquo;t change as quickly as the average rating given by a user to different items. It&amp;rsquo;s also known to perform better than the user-based approach when the ratings matrix is sparse.&lt;/p&gt;
&lt;p&gt;Although, the item-based approach performs poorly for datasets with browsing or entertainment related items such as MovieLens, where the recommendations it gives out seem very obvious to the target users. Such datasets see better results with matrix factorization techniques, which you&amp;rsquo;ll see in the next section, or with hybrid recommenders that also take into account the content of the data like the genre by using &lt;a href=&quot;https://en.wikipedia.org/wiki/Recommender_system#Content-based_filtering&quot;&gt;content-based filtering&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;You can use the library &lt;a href=&quot;https://github.com/NicolasHug/Surprise&quot;&gt;Surprise&lt;/a&gt; to experiment with different recommender algorithms quickly. (You will see more about this later in the article.)&lt;/p&gt;
&lt;h2 id=&quot;model-based&quot;&gt;Model Based&lt;/h2&gt;
&lt;p&gt;The second category covers the Model based approaches, which involve a step to reduce or compress the large but sparse user-item matrix. For understanding this step, a basic understanding of dimensionality reduction can be very helpful.&lt;/p&gt;
&lt;h3 id=&quot;dimensionality-reduction&quot;&gt;Dimensionality Reduction&lt;/h3&gt;
&lt;p&gt;In the user-item matrix, there are two dimensions:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The number of users&lt;/li&gt;
&lt;li&gt;The number of items&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;If the matrix is mostly empty, reducing dimensions can improve the performance of the algorithm in terms of both space and time. You can use various methods like matrix factorization or autoencoders to do this.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Matrix factorization&lt;/strong&gt; can be seen as breaking down a large matrix into a product of smaller ones. This is similar to the factorization of integers, where &lt;code&gt;12&lt;/code&gt; can be written as &lt;code&gt;6 x 2&lt;/code&gt; or &lt;code&gt;4 x 3&lt;/code&gt;. In the case of matrices, a matrix &lt;strong&gt;A&lt;/strong&gt; with dimensions &lt;code&gt;m x n&lt;/code&gt; can be reduced to a product of two matrices &lt;strong&gt;X&lt;/strong&gt; and &lt;strong&gt;Y&lt;/strong&gt; with dimensions &lt;code&gt;m x p&lt;/code&gt; and &lt;code&gt;p x n&lt;/code&gt; respectively.&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; In matrix multiplication, a matrix &lt;strong&gt;X&lt;/strong&gt; can be multiplied by &lt;strong&gt;Y&lt;/strong&gt; only if the number of columns in &lt;strong&gt;X&lt;/strong&gt; is equal to the number of rows in &lt;strong&gt;Y&lt;/strong&gt;. 
Therefore the two reduced matrices have a common dimension &lt;strong&gt;p&lt;/strong&gt;. &lt;/p&gt;
&lt;p&gt;Depending on the algorithm used for dimensionality reduction, the number of reduced matrices can be more than two as well.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;The reduced matrices actually represent the users and items individually. The &lt;strong&gt;m&lt;/strong&gt; rows in the first matrix represent the &lt;strong&gt;m&lt;/strong&gt; users, and the &lt;strong&gt;p&lt;/strong&gt; columns tell you about the features or characteristics of the users. The same goes for the item matrix with &lt;strong&gt;n&lt;/strong&gt; items and &lt;strong&gt;p&lt;/strong&gt; characteristics. Here&amp;rsquo;s an example of how matrix factorization looks:&lt;/p&gt;
&lt;figure class=&quot;figure mx-auto d-block&quot;&gt;&lt;a href=&quot;https://files.realpython.com/media/dimensionality-reduction.f8686dd52b9c.jpg&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/dimensionality-reduction.f8686dd52b9c.jpg&quot; width=&quot;802&quot; height=&quot;648&quot; srcset=&quot;https://robocrop.realpython.net/?url=https%3A//files.realpython.com/media/dimensionality-reduction.f8686dd52b9c.jpg&amp;amp;w=200&amp;amp;sig=f955c65b75481236b7e345da021cecb7723cad92 200w, https://robocrop.realpython.net/?url=https%3A//files.realpython.com/media/dimensionality-reduction.f8686dd52b9c.jpg&amp;amp;w=401&amp;amp;sig=373cf3b1c688b76da2e23c228a0f0b274b97debc 401w, https://files.realpython.com/media/dimensionality-reduction.f8686dd52b9c.jpg 802w&quot; sizes=&quot;75vw&quot; alt=&quot;A matrix factorized into two matrices using dimensionality reduction&quot;/&gt;&lt;/a&gt;&lt;figcaption class=&quot;figure-caption text-center&quot;&gt;Matrix Factorization&lt;/figcaption&gt;&lt;/figure&gt;

&lt;p&gt;In the image above, the matrix is reduced into two matrices. The one on the left is the user matrix with &lt;em&gt;m&lt;/em&gt; users, and the one on top is the item matrix with &lt;em&gt;n&lt;/em&gt; items. The rating &lt;code&gt;4&lt;/code&gt; is reduced or factorized into:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;A user vector &lt;code&gt;(2, -1)&lt;/code&gt; &lt;/li&gt;
&lt;li&gt;An item vector &lt;code&gt;(2.5, 1)&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The two columns in the user matrix and the two rows in the item matrix are called latent factors and are an indication of hidden characteristics about the users or the items. A possible interpretation of the factorization could look like this:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Assume that in a user vector &lt;code&gt;(u, v)&lt;/code&gt;, &lt;code&gt;u&lt;/code&gt; represents how much a user likes the Horror genre, and &lt;code&gt;v&lt;/code&gt; represents how much they like the Romance genre.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The user vector &lt;code&gt;(2, -1)&lt;/code&gt; thus represents a user who likes horror movies and rates them positively and dislikes movies that have romance and rates them negatively.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Assume that in an item vector &lt;code&gt;(i, j)&lt;/code&gt;, &lt;code&gt;i&lt;/code&gt; represents how much a movie belongs to the Horror genre, and &lt;code&gt;j&lt;/code&gt; represents how much that movie belongs to the Romance genre.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The movie &lt;code&gt;(2.5, 1)&lt;/code&gt; has a Horror rating of &lt;code&gt;2.5&lt;/code&gt; and a Romance rating of &lt;code&gt;1&lt;/code&gt;. Multiplying it by the user vector using matrix multiplication rules gives you &lt;code&gt;(2 * 2.5) + (-1 * 1) = 4&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;So, the movie belonged to the Horror genre, and the user could have rated it &lt;code&gt;5&lt;/code&gt;, but the slight inclusion of Romance caused the final rating to drop to &lt;code&gt;4&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The factor matrices can provide such insights about users and items, but in reality they are usually much more complex than the explanation given above. The number of such factors can be anything from one to hundreds or even thousands. This number is one of the things that need to be optimized during the training of the model.&lt;/p&gt;
&lt;p&gt;In the example, you had two latent factors for movie genres, but in real scenarios, these latent factors need not be analyzed too much. These are patterns in the data that will play their part automatically whether you decipher their underlying meaning or not.&lt;/p&gt;
&lt;p&gt;The number of latent factors affects the recommendations in a manner where the greater the number of factors, the more personalized the recommendations become. But too many factors can lead to overfitting in the model.&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;strong&gt;Overfitting&lt;/strong&gt; happens when the model trains to fit the training data so well that it doesn&amp;rsquo;t perform well with new data.&lt;/p&gt;
&lt;/div&gt;
&lt;h3 id=&quot;algorithms-for-matrix-factorization&quot;&gt;Algorithms for Matrix Factorization&lt;/h3&gt;
&lt;p&gt;One of the popular algorithms to factorize a matrix is the &lt;a href=&quot;https://en.wikipedia.org/wiki/Singular_value_decomposition&quot;&gt;singular value decomposition&lt;/a&gt; (SVD) algorithm. SVD came into the limelight when matrix factorization was seen performing well in the Netflix prize competition. Other algorithms include &lt;a href=&quot;https://en.wikipedia.org/wiki/Principal_component_analysis&quot;&gt;PCA&lt;/a&gt; and its variations, &lt;a href=&quot;https://en.wikipedia.org/wiki/Non-negative_matrix_factorization&quot;&gt;NMF&lt;/a&gt;, and so on. &lt;a href=&quot;https://en.wikipedia.org/wiki/Autoencoder&quot;&gt;Autoencoders&lt;/a&gt; can also be used for dimensionality reduction in case you want to use Neural Networks.&lt;/p&gt;
&lt;p&gt;You can find the implementations of these algorithms in various libraries for Python so you don&amp;rsquo;t need to worry about the details at this point. But in case you want to read more, the chapter on dimensionality reduction in the book &lt;a href=&quot;http://www.mmds.org/&quot;&gt;&lt;em&gt;Mining of Massive Datasets&lt;/em&gt;&lt;/a&gt; is worth a read.&lt;/p&gt;
&lt;h2 id=&quot;using-python-to-build-recommenders&quot;&gt;Using Python to Build Recommenders&lt;/h2&gt;
&lt;p&gt;There are quite a few libraries and toolkits in Python that provide implementations of various algorithms that you can use to build a recommender. But the one that you should try out while understanding recommendation systems is &lt;a href=&quot;https://github.com/NicolasHug/Surprise&quot;&gt;Surprise&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Surprise is a Python &lt;a href=&quot;https://www.scipy.org/scikits.html&quot;&gt;SciKit&lt;/a&gt; that comes with various recommender algorithms and similarity metrics to make it easy to build and analyze recommenders.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s how to install it using pip:&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 numpy
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; pip install scikit-surprise
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Here&amp;rsquo;s how to install it using conda:&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; conda install -c conda-forge scikit-surprise
&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; Installing &lt;a href=&quot;https://realpython.com/courses/introduction-pandas-and-vincent/&quot;&gt;Pandas&lt;/a&gt; is also recommended if you wish to follow the examples. &lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;To use Surprise, you should first know some of the basic &lt;a href=&quot;https://realpython.com/python-modules-packages/&quot;&gt;modules&lt;/a&gt; and &lt;a href=&quot;https://realpython.com/lessons/classes-python/&quot;&gt;classes&lt;/a&gt; available in it:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;The &lt;code&gt;Dataset&lt;/code&gt; module is used to load data from files, &lt;a href=&quot;https://realpython.com/courses/pandas-dataframes-101/&quot;&gt;Pandas dataframes&lt;/a&gt;, or even built-in datasets available for experimentation. (MovieLens 100k is one of the built-in datasets in Surprise.) To load a dataset, some of the available methods are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Dataset.load_builtin()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Dataset.load_from_file()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Dataset.load_from_df()&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The &lt;code&gt;Reader&lt;/code&gt; class is used to parse a file containing ratings. The default format in which it accepts data is that each rating is stored in a separate line in the order &lt;code&gt;user item rating&lt;/code&gt;. This order and the separator can be configured using parameters:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;line_format&lt;/code&gt;&lt;/strong&gt; is a &lt;a href=&quot;https://realpython.com/python-strings/&quot;&gt;string&lt;/a&gt; that stores the order of the data with field names separated by a space, as in &lt;code&gt;&quot;item user rating&quot;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;sep&lt;/code&gt;&lt;/strong&gt; is used to specify separator between fields, such as &lt;code&gt;&#39;,&#39;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;rating_scale&lt;/code&gt;&lt;/strong&gt; is used to specify the rating scale. The default is &lt;code&gt;(1, 5)&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;skip_lines&lt;/code&gt;&lt;/strong&gt; is used to indicate the number of lines to skip at the beginning of the file. The default is &lt;code&gt;0&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Here&amp;rsquo;s a program that you can use to load data from a Pandas dataframe or the from builtin MovieLens 100k dataset:&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;# load_data.py&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;pandas&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;pd&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;surprise&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Dataset&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;surprise&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Reader&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# This is the same data that was plotted for similarity earlier&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# with one new user &amp;quot;E&amp;quot; who has rated only movie 1&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;ratings_dict&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;item&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;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;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;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;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;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
    &lt;span class=&quot;s2&quot;&gt;&amp;quot;user&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;s1&quot;&gt;&amp;#39;A&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;A&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;B&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;B&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;C&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;C&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;D&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;D&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;E&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
    &lt;span class=&quot;s2&quot;&gt;&amp;quot;rating&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;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;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;mf&quot;&gt;2.5&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;mf&quot;&gt;4.5&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;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;df&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pd&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;DataFrame&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ratings_dict&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;reader&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Reader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rating_scale&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;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Loads Pandas dataframe&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;Dataset&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;load_from_df&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;df&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;user&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;item&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;rating&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]],&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;reader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# Loads the builtin Movielens-100k data&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;movielens&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Dataset&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;load_builtin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;ml-100k&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 the above program, the data is stored in a dictionary that is loaded into a Pandas dataframe and then into a Dataset object from Surprise.&lt;/p&gt;
&lt;h3 id=&quot;algorithms-based-on-k-nearest-neighbours-k-nn&quot;&gt;Algorithms Based on K-Nearest Neighbours (k-NN)&lt;/h3&gt;
&lt;p&gt;The choice of algorithm for the recommender function depends on the technique you want to use. For the memory-based approaches discussed above, the algorithm that would fit the bill is &lt;a href=&quot;https://surprise.readthedocs.io/en/stable/knn_inspired.html#surprise.prediction_algorithms.knns.KNNWithMeans&quot;&gt;Centered k-NN&lt;/a&gt; because the algorithm is very close to the centered cosine similarity formula explained above. It is available in Surprise as &lt;code&gt;KNNWithMeans&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;To find the similarity, you simply have to configure the function by passing a dictionary as an argument to the recommender function. The dictionary should have the required keys, such as the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;name&lt;/code&gt;&lt;/strong&gt; contains the similarity metric to use. Options are &lt;code&gt;cosine&lt;/code&gt;, &lt;code&gt;msd&lt;/code&gt;, &lt;code&gt;pearson&lt;/code&gt;, or &lt;code&gt;pearson_baseline&lt;/code&gt;. The default is &lt;a href=&quot;https://surprise.readthedocs.io/en/stable/similarities.html#surprise.similarities.msd&quot;&gt;&lt;code&gt;msd&lt;/code&gt;&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;user_based&lt;/code&gt;&lt;/strong&gt; is a &lt;code&gt;boolean&lt;/code&gt; that tells whether the approach will be user-based or item-based. The default is &lt;code&gt;True&lt;/code&gt;, which means the user-based approach will be used.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;min_support&lt;/code&gt;&lt;/strong&gt; is the minimum number of common items needed between users to consider them for similarity. For the item-based approach, this corresponds to the minimum number of common users for two items.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The following program configures the &lt;code&gt;KNNWithMeans&lt;/code&gt; function:&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;# recommender.py&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;surprise&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;KNNWithMeans&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# To use item-based cosine similarity&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;sim_options&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;name&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;cosine&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s2&quot;&gt;&amp;quot;user_based&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&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;c1&quot;&gt;# Compute  similarities between items&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;algo&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;KNNWithMeans&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sim_options&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sim_options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The recommender function in the above program is configured to use the cosine similarity and to find similar items using the item-based approach.&lt;/p&gt;
&lt;p&gt;To try out this recommender, you need to create a &lt;code&gt;Trainset&lt;/code&gt; from &lt;code&gt;data&lt;/code&gt;. &lt;code&gt;Trainset&lt;/code&gt; is built using the same data but contains more information about the data, such as the number of users and items (&lt;code&gt;n_users&lt;/code&gt;, &lt;code&gt;n_items&lt;/code&gt;) that are used by the algorithm. You can create it either by using the entire data or a part of the data. You can also divide the data into folds where some of the data will be used for training and some for testing.&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 only one pair of training and testing data is usually not enough. When you split the original dataset into training and testing data, you should create more than one pair to allow for multiple observations with variations in the training in testing data.&lt;/p&gt;
&lt;p&gt;Algorithms should be &lt;a href=&quot;https://en.wikipedia.org/wiki/Cross-validation_(statistics)&quot;&gt;cross-validated&lt;/a&gt; using multiple folds. By using different pairs, you&amp;rsquo;ll see different results given by your recommender. MovieLens 100k provides five different splits of training and testing data: u1.base, u1.test, u2.base, u2.test &amp;hellip; u5.base, u5.test, for a 5-fold cross-validation&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;Here&amp;rsquo;s an example to find out how the user &lt;strong&gt;E&lt;/strong&gt; would rate the movie 2:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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;load_data&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;data&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;recommender&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;algo&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;trainingSet&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;build_full_trainset&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;algo&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;trainingSet&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Computing the cosine similarity matrix...&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Done computing similarity matrix.&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;&amp;lt;surprise.prediction_algorithms.knns.KNNWithMeans object at 0x7f04fec56898&amp;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;prediction&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;algo&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;s1&quot;&gt;&amp;#39;E&amp;#39;&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;n&quot;&gt;prediction&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;est&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;4.15&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The algorithm predicted that the user &lt;strong&gt;E&lt;/strong&gt; would rate the movie 4.15, which could be high enough to be shown as a recommendation.&lt;/p&gt;
&lt;p&gt;You should try out the different &lt;a href=&quot;https://surprise.readthedocs.io/en/stable/knn_inspired.html&quot;&gt;k-NN based algorithms&lt;/a&gt; along with different similarity options and &lt;a href=&quot;https://surprise.readthedocs.io/en/stable/matrix_factorization.html&quot;&gt;matrix factorization algorithms&lt;/a&gt; available in the Surprise library. Try them out on the MovieLens dataset to see if you can beat some benchmarks. The next section will cover how to use Surprise to check which parameters perform best for your data.&lt;/p&gt;
&lt;h3 id=&quot;tuning-the-algorithm-parameters&quot;&gt;Tuning the Algorithm Parameters&lt;/h3&gt;
&lt;p&gt;Surprise provides a &lt;code&gt;GridSearchCV&lt;/code&gt; class analogous to &lt;a href=&quot;https://scikit-learn.org/stable/modules/generated/sklearn.model_selection.GridSearchCV.html&quot;&gt;GridSearchCV&lt;/a&gt; from &lt;code&gt;scikit-learn&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;With a &lt;code&gt;dict&lt;/code&gt; of all parameters, &lt;code&gt;GridSearchCV&lt;/code&gt; tries all the combinations of parameters and reports the best parameters for any accuracy measure&lt;/p&gt;
&lt;p&gt;For example, you can check which similarity metric works best for your data in memory-based approaches:&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;surprise&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;KNNWithMeans&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;surprise&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Dataset&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;surprise.model_selection&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;GridSearchCV&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;Dataset&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;load_builtin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;ml-100k&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;sim_options&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;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;s2&quot;&gt;&amp;quot;msd&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;cosine&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
    &lt;span class=&quot;s2&quot;&gt;&amp;quot;min_support&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;mi&quot;&gt;3&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;s2&quot;&gt;&amp;quot;user_based&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;kc&quot;&gt;False&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;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;param_grid&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;sim_options&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sim_options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;gs&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;GridSearchCV&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;KNNWithMeans&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;param_grid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;measures&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;rmse&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;mae&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cv&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;gs&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;data&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;gs&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;best_score&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;rmse&amp;quot;&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;gs&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;best_params&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;rmse&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 output of the above program is as follows:&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;0.9434791128171457&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;{&amp;#39;sim_options&amp;#39;: {&amp;#39;name&amp;#39;: &amp;#39;msd&amp;#39;, &amp;#39;min_support&amp;#39;: 3, &amp;#39;user_based&amp;#39;: False}}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;So, for the MovieLens 100k dataset, Centered-KNN algorithm works best if you go with item-based approach and use msd as the similarity metric with minimum support 3.&lt;/p&gt;
&lt;p&gt;Similarly, for model-based approaches, we can use &lt;code&gt;Surprise&lt;/code&gt; to check which values for the following factors work best:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;n_epochs&lt;/code&gt;&lt;/strong&gt; is the number of iterations of SGD, which is basically an iterative method used in Statistics to minimize a function.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;lr_all&lt;/code&gt;&lt;/strong&gt; is the learning rate for all parameters, which is a parameter that decides how much the parameters are adjusted in each iteration.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;reg_all&lt;/code&gt;&lt;/strong&gt; is the regularization term for all parameters, which is a penalty term added to prevent overfitting.&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; Keep in mind that there won&amp;rsquo;t be any similarity metrics in matrix factorization algorithms as the latent factors take care of similarity among users or items.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;The following program will check the best values for the &lt;a href=&quot;https://surprise.readthedocs.io/en/stable/matrix_factorization.html#surprise.prediction_algorithms.matrix_factorization.SVDpp&quot;&gt;SVD&lt;/a&gt; algorithm, which is a matrix factorization algorithm:&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;surprise&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SVD&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;surprise&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Dataset&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;surprise.model_selection&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;GridSearchCV&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;Dataset&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;load_builtin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;ml-100k&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;param_grid&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;n_epochs&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;mi&quot;&gt;5&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;s2&quot;&gt;&amp;quot;lr_all&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;mf&quot;&gt;0.002&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.005&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
    &lt;span class=&quot;s2&quot;&gt;&amp;quot;reg_all&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;mf&quot;&gt;0.4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.6&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;gs&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;GridSearchCV&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SVD&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;param_grid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;measures&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;rmse&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;mae&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cv&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;gs&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;data&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;gs&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;best_score&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;rmse&amp;quot;&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;gs&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;best_params&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;rmse&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 output of the above program is as follows:&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;0.9642278631521038&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;{&amp;#39;n_epochs&amp;#39;: 10, &amp;#39;lr_all&amp;#39;: 0.005, &amp;#39;reg_all&amp;#39;: 0.4}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;So, for the MovieLens 100k dataset, the &lt;code&gt;SVD&lt;/code&gt; algorithm works best if you go with 10 epochs and use a learning rate of 0.005 and 0.4 regularization. &lt;/p&gt;
&lt;p&gt;Other Matrix Factorization based algorithms available in &lt;code&gt;Surprise&lt;/code&gt; are &lt;a href=&quot;https://surprise.readthedocs.io/en/stable/matrix_factorization.html#surprise.prediction_algorithms.matrix_factorization.SVDpp&quot;&gt;SVD++&lt;/a&gt; and &lt;a href=&quot;https://surprise.readthedocs.io/en/stable/matrix_factorization.html#surprise.prediction_algorithms.matrix_factorization.SVDpp&quot;&gt;NMF&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Following these examples, you can dive deep into all the parameters that can be used in these algorithms. You should definitely check out the mathematics behind them. Since you won&amp;rsquo;t have to worry much about the implementation of algorithms initially, recommenders can be a great way to segue into the field of machine learning and build an application based on that.&lt;/p&gt;
&lt;h2 id=&quot;when-can-collaborative-filtering-be-used&quot;&gt;When Can Collaborative Filtering Be Used?&lt;/h2&gt;
&lt;p&gt;Collaborative filtering works around the interactions that users have with items. These interactions can help find patterns that the data about the items or users itself can&amp;rsquo;t. Here are some points that can help you decide if collaborative filtering can be used:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Collaborative filtering doesn&amp;rsquo;t require features about the items or users to be known. It is suited for a set of different types of items, for example, a supermarket&amp;rsquo;s inventory where items of various categories can be added. In a set of similar items such as that of a bookstore, though, known features like writers and genres can be useful and might benefit from content-based or hybrid approaches.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Collaborative filtering can help recommenders to not overspecialize in a user&amp;rsquo;s profile and recommend items that are completely different from what they have seen before. If you want your recommender to not suggest a pair of sneakers to someone who just bought another similar pair of sneakers, then try to add collaborative filtering to your recommender spell.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Although collaborative Filtering is very commonly used in recommenders, some of the challenges that are faced while using it are the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Collaborative filtering can lead to some problems like cold start for new items that are added to the list. Until someone rates them, they don&amp;rsquo;t get recommended.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Data sparsity can affect the quality of user-based recommenders and also add to the cold start problem mentioned above.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Scaling can be a challenge for growing datasets as the complexity can become too large. Item-based recommenders are faster than user-based when the dataset is large.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;With a straightforward implementation, you might observe that the recommendations tend to be already popular, and the items from the &lt;a href=&quot;https://en.wikipedia.org/wiki/Long_tail&quot;&gt;long tail&lt;/a&gt; section might get ignored.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;With every type of recommender algorithm having its own list of pros and cons, it&amp;rsquo;s usually a hybrid recommender that comes to the rescue. The benefits of multiple algorithms working together or in a pipeline can help you set up more accurate recommenders. In fact, the solution of the winner of the Netflix prize was also a complex mix of multiple algorithms.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;You now know what calculations go into a collaborative-filtering type recommender and how to try out the various types of algorithms quickly on your dataset to see if collaborative filtering is the way to go. Even if it does not seem to fit your data with high accuracy, some of the use cases discussed might help you plan things in a hybrid way for the long term.&lt;/p&gt;
&lt;p&gt;Here are some resources for more implementations and further reading on collaborative filtering and other recommendation algorithms.&lt;/p&gt;
&lt;p&gt;Libraries:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://github.com/lyst/lightfm&quot;&gt;LightFM&lt;/a&gt;:&lt;/strong&gt; a hybrid recommendation algorithm in Python&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://github.com/ocelma/python-recsys&quot;&gt;Python-recsys&lt;/a&gt;:&lt;/strong&gt; a Python library for implementing a recommender system&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Research papers:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;http://files.grouplens.org/papers/www10_sarwar.pdf&quot;&gt;Item Based Collaborative Filtering Recommendation Algorithms&lt;/a&gt;:&lt;/strong&gt; the first paper published on item-based recommenders&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://scinapse.io/papers/1966553486&quot;&gt;Using collaborative filtering to weave an information tapestry&lt;/a&gt;:&lt;/strong&gt; the first use of the term collaborative filtering&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Books:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;http://www.mmds.org/&quot;&gt;&lt;em&gt;Mining of Massive Datasets&lt;/em&gt;&lt;/a&gt;&lt;/strong&gt; by Jure Leskovec, Anand Rajaraman, Jeff Ullman&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;em&gt;Programming Collective Intelligence&lt;/em&gt;&lt;/strong&gt; by Toby Segaran&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>Reading and Writing Files in Python</title>
      <id>https://realpython.com/courses/reading-and-writing-files-python/</id>
      <link href="https://realpython.com/courses/reading-and-writing-files-python/"/>
      <updated>2019-07-09T14:00:00+00:00</updated>
      <summary>In this course, you&#39;ll learn about reading and writing files in Python. You&#39;ll cover everything from what a file is made up of to which libraries can help you along that way. You&#39;ll also take a look at some basic scenarios of file usage as well as some advanced techniques.</summary>
      <content type="html">
        &lt;p&gt;In this course, you&amp;rsquo;ll learn about reading and writing files in Python. You&amp;rsquo;ll cover everything from what a file is made up of to which libraries can help you along that way. You&amp;rsquo;ll also take a look at some basic scenarios of file usage as well as some advanced techniques.&lt;/p&gt;
&lt;p&gt;One of the most common tasks that you can do with Python is reading and writing files. Whether it’s writing to a simple text file, reading a complicated server log, or even analyzing raw byte data, all of these situations require reading or writing a file.&lt;/p&gt;
&lt;p&gt;By the end of this course, you’ll know:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;What makes up a file and why that’s important in Python&lt;/li&gt;
&lt;li&gt;The basics of reading and writing files in Python&lt;/li&gt;
&lt;li&gt;Some basic scenarios of reading and writing files&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This tutorial is mainly for beginner to intermediate Pythonistas, but there are some tips in here that more advanced programmers may appreciate as well.&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>The Python Square Root Function</title>
      <id>https://realpython.com/python-square-root-function/</id>
      <link href="https://realpython.com/python-square-root-function/"/>
      <updated>2019-07-08T14:00:00+00:00</updated>
      <summary>In this quick and practical tutorial, you&#39;ll learn what a square root is and how to calculate one in Python. You&#39;ll even see how you can use the Python square root function to solve a real-world problem.</summary>
      <content type="html">
        &lt;p&gt;Are you trying to solve a quadratic equation? Maybe you need to calculate the length of one side of a right triangle. For these types of equations and more, the Python square root function, &lt;strong&gt;&lt;code&gt;sqrt()&lt;/code&gt;&lt;/strong&gt;, can help you quickly and accurately calculate your solutions.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;By the end of this article, you&amp;rsquo;ll learn:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;What a square root is&lt;/li&gt;
&lt;li&gt;How to use the Python square root function, &lt;code&gt;sqrt()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;When &lt;code&gt;sqrt()&lt;/code&gt; can be useful in the real world&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Let&amp;rsquo;s dive in!&lt;/p&gt;
&lt;div class=&quot;alert alert-primary&quot; role=&quot;alert&quot;&gt;
&lt;p&gt;&lt;strong&gt;Python Pit Stop:&lt;/strong&gt; This tutorial is a &lt;strong&gt;quick&lt;/strong&gt; and &lt;strong&gt;practical&lt;/strong&gt; way to find the info you need, so you&amp;rsquo;ll be back to your project in no time!&lt;/p&gt;
&lt;/div&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;square-roots-in-mathematics&quot;&gt;Square Roots in Mathematics&lt;/h2&gt;
&lt;p&gt;In algebra, a &lt;strong&gt;square&lt;/strong&gt;, &lt;em&gt;x&lt;/em&gt;, is the result of a number, &lt;em&gt;n&lt;/em&gt;, multiplied by itself: &lt;em&gt;x = n²&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;You can calculate squares using Python:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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;n&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;gp&quot;&gt;&amp;gt;&amp;gt;&amp;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;n&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;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;25&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The Python &lt;code&gt;**&lt;/code&gt; operator is used for calculating the power of a number. In this case, 5 squared, or 5 to the power of 2, is 25.&lt;/p&gt;
&lt;p&gt;The square root, then, is the number &lt;em&gt;n&lt;/em&gt;, which when multiplied by itself yields the square, &lt;em&gt;x&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;In this example, &lt;em&gt;n&lt;/em&gt;, the square root, is 5.&lt;/p&gt;
&lt;p&gt;25 is an example of a &lt;strong&gt;perfect square&lt;/strong&gt;. Perfect squares are the squares of integer values:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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;1&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;go&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;mi&quot;&gt;2&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;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;mi&quot;&gt;3&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;go&quot;&gt;9&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You might have memorized some of these perfect squares when you learned your multiplication tables in an elementary algebra class.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re given a small perfect square, it may be straightforward enough to calculate or memorize its square root. But for most other squares, this calculation can get a bit more tedious. Often, an estimation is good enough when you don&amp;rsquo;t have a calculator.&lt;/p&gt;
&lt;p&gt;Fortunately, as a Python developer, you do have a calculator, namely the &lt;a href=&quot;https://realpython.com/interacting-with-python/#using-the-python-interpreter-interactively&quot;&gt;Python interpreter&lt;/a&gt;!&lt;/p&gt;
&lt;h2 id=&quot;the-python-square-root-function&quot;&gt;The Python Square Root Function&lt;/h2&gt;
&lt;p&gt;Python&amp;rsquo;s &lt;a href=&quot;https://docs.python.org/3/library/math.html&quot;&gt;&lt;code&gt;math&lt;/code&gt; module&lt;/a&gt;, in the standard library, can help you work on math-related problems in code. It contains many useful functions, such as &lt;code&gt;remainder()&lt;/code&gt; and &lt;code&gt;factorial()&lt;/code&gt;. It also includes the &lt;a href=&quot;https://docs.python.org/3/library/math.html#math.sqrt&quot;&gt;Python square root function, &lt;code&gt;sqrt()&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;You&amp;rsquo;ll begin by &lt;a href=&quot;https://realpython.com/absolute-vs-relative-python-imports/&quot;&gt;importing&lt;/a&gt; &lt;code&gt;math&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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;math&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;That&amp;rsquo;s all it takes! You can now use &lt;code&gt;math.sqrt()&lt;/code&gt; to calculate square roots.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;sqrt()&lt;/code&gt; has a straightforward interface.&lt;/p&gt;
&lt;p&gt;It takes one parameter, &lt;code&gt;x&lt;/code&gt;, which (as you saw before) stands for the square for which you are trying to calculate the square root. In the example from earlier, this would be &lt;code&gt;25&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The return value of &lt;code&gt;sqrt()&lt;/code&gt; is the square root of &lt;code&gt;x&lt;/code&gt;, as a &lt;a href=&quot;https://realpython.com/python-data-types/#floating-point-numbers&quot;&gt;floating point number&lt;/a&gt;. In the example, this would be &lt;code&gt;5.0&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s take a look at some examples of how to (and how not to) use &lt;code&gt;sqrt()&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;the-square-root-of-a-positive-number&quot;&gt;The Square Root of a Positive Number&lt;/h3&gt;
&lt;p&gt;One type of argument you can pass to &lt;code&gt;sqrt()&lt;/code&gt; is a positive number. This includes both &lt;a href=&quot;https://realpython.com/python-data-types/#integers&quot;&gt;&lt;code&gt;int&lt;/code&gt;&lt;/a&gt; and &lt;a href=&quot;https://realpython.com/python-data-types/#floating-point-numbers&quot;&gt;&lt;code&gt;float&lt;/code&gt;&lt;/a&gt; types.&lt;/p&gt;
&lt;p&gt;For example, you can solve for the square root of &lt;code&gt;49&lt;/code&gt; using &lt;code&gt;sqrt()&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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;math&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sqrt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;49&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;7.0&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The return value is &lt;code&gt;7.0&lt;/code&gt; (the square root of &lt;code&gt;49&lt;/code&gt;) as a floating point number.&lt;/p&gt;
&lt;p&gt;Along with integers, you can also pass &lt;code&gt;float&lt;/code&gt; values:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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;math&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sqrt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;70.5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;8.396427811873332&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You can verify the accuracy of this square root by calculating its inverse:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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;mf&quot;&gt;8.396427811873332&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;go&quot;&gt;70.5&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id=&quot;the-square-root-of-zero&quot;&gt;The Square Root of Zero&lt;/h3&gt;
&lt;p&gt;Even &lt;code&gt;0&lt;/code&gt; is a valid square to pass to the Python square root function:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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;math&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sqrt&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;0.0&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;While you probably won&amp;rsquo;t need to calculate the square root of zero often, you may be passing a variable to &lt;code&gt;sqrt()&lt;/code&gt; whose value you don&amp;rsquo;t actually know. So, it&amp;rsquo;s good to know that it can handle zero in those cases.&lt;/p&gt;
&lt;h3 id=&quot;the-square-root-of-negative-numbers&quot;&gt;The Square Root of Negative Numbers&lt;/h3&gt;
&lt;p&gt;The square of any &lt;a href=&quot;https://en.wikipedia.org/wiki/Real_number&quot;&gt;real number&lt;/a&gt; cannot be negative. This is because a negative product is only possible if one factor is positive and the other is negative. A square, by definition, is the product of a number and itself, so it&amp;rsquo;s impossible to have a negative real square:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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;math&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sqrt&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;25&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;gt&quot;&gt;Traceback (most recent call last):&lt;/span&gt;
  File &lt;span class=&quot;nb&quot;&gt;&amp;quot;&amp;lt;stdin&amp;gt;&amp;quot;&lt;/span&gt;, line &lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;, in &lt;span class=&quot;n&quot;&gt;&amp;lt;module&amp;gt;&lt;/span&gt;
&lt;span class=&quot;gr&quot;&gt;ValueError&lt;/span&gt;: &lt;span class=&quot;n&quot;&gt;math domain error&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;If you attempt to pass a negative number to &lt;code&gt;sqrt()&lt;/code&gt;, then you&amp;rsquo;ll get a &lt;code&gt;ValueError&lt;/code&gt; because negative numbers are not in the domain of possible real squares. Instead, the square root of a negative number would need to be &lt;a href=&quot;https://en.wikipedia.org/wiki/Complex_number&quot;&gt;complex&lt;/a&gt;, which is outside the scope of the Python square root function.&lt;/p&gt;
&lt;h2 id=&quot;square-roots-in-the-real-world&quot;&gt;Square Roots in the Real World&lt;/h2&gt;
&lt;p&gt;To see a real-world application of the Python square root function, let&amp;rsquo;s turn to the sport of tennis.&lt;/p&gt;
&lt;p&gt;Imagine that &lt;a href=&quot;https://en.wikipedia.org/wiki/Rafael_Nadal&quot;&gt;Rafael Nadal&lt;/a&gt;, one of the fastest players in the world, has just hit a forehand from the back corner, where the baseline meets the sideline of the &lt;a href=&quot;https://en.wikipedia.org/wiki/Tennis_court&quot;&gt;tennis court&lt;/a&gt;:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://files.realpython.com/media/untitled.b0437a7fab5e.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/untitled.b0437a7fab5e.png&quot; width=&quot;676&quot; height=&quot;513&quot; srcset=&quot;https://robocrop.realpython.net/?url=https%3A//files.realpython.com/media/untitled.b0437a7fab5e.png&amp;amp;w=169&amp;amp;sig=62bf1c2f3069b25c9911a1f52abc85df12613b84 169w, https://robocrop.realpython.net/?url=https%3A//files.realpython.com/media/untitled.b0437a7fab5e.png&amp;amp;w=338&amp;amp;sig=d6f49ab7026b1a4963bc3fcbed64dee2797123f0 338w, https://files.realpython.com/media/untitled.b0437a7fab5e.png 676w&quot; sizes=&quot;75vw&quot; alt=&quot;Python Pit Stop: Tennis Ball Hit From Baseline&quot;/&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Now, assume his opponent has countered with a drop shot (one that would place the ball short with little forward momentum) to the opposite corner, where the other sideline meets the net:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://files.realpython.com/media/untitled_1.9226ba6799b4.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/untitled_1.9226ba6799b4.png&quot; width=&quot;676&quot; height=&quot;513&quot; srcset=&quot;https://robocrop.realpython.net/?url=https%3A//files.realpython.com/media/untitled_1.9226ba6799b4.png&amp;amp;w=169&amp;amp;sig=b6c3022e18447b436c765108b7f905d685f96cb5 169w, https://robocrop.realpython.net/?url=https%3A//files.realpython.com/media/untitled_1.9226ba6799b4.png&amp;amp;w=338&amp;amp;sig=cb42946de4ec0bbe2432b926bcc47336b114059e 338w, https://files.realpython.com/media/untitled_1.9226ba6799b4.png 676w&quot; sizes=&quot;75vw&quot; alt=&quot;Python Pit Stop: Tennis Ball Returned At The Net&quot;/&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;How far must Nadal run to reach the ball?&lt;/p&gt;
&lt;p&gt;You can determine from &lt;a href=&quot;https://en.wikipedia.org/wiki/Tennis_court#/media/File:Tennis_court_imperial.svg&quot;&gt;regulation tennis court dimensions&lt;/a&gt; that the baseline is 27 feet long, and the sideline (on one side of the net) is 39 feet long. So, essentially, this boils down to solving for the hypotenuse of a right triangle:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://files.realpython.com/media/Tennis_Court_1.12dcfe313971.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/Tennis_Court_1.12dcfe313971.png&quot; width=&quot;676&quot; height=&quot;513&quot; srcset=&quot;https://robocrop.realpython.net/?url=https%3A//files.realpython.com/media/Tennis_Court_1.12dcfe313971.png&amp;amp;w=169&amp;amp;sig=26aff62dbc00b874066949aac6d61966d8f9840a 169w, https://robocrop.realpython.net/?url=https%3A//files.realpython.com/media/Tennis_Court_1.12dcfe313971.png&amp;amp;w=338&amp;amp;sig=c7620a201a32bfc887c440dd8a52ef2f91959c90 338w, https://files.realpython.com/media/Tennis_Court_1.12dcfe313971.png 676w&quot; sizes=&quot;75vw&quot; alt=&quot;Python Pit Stop: Solving For The Hypotenuse Using The Square Root&quot;/&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Using a valuable equation from geometry, the &lt;a href=&quot;https://en.wikipedia.org/wiki/Pythagorean_theorem&quot;&gt;Pythagorean theorem&lt;/a&gt;, we know that &lt;em&gt;a² + b² = c²&lt;/em&gt;, where &lt;em&gt;a&lt;/em&gt; and &lt;em&gt;b&lt;/em&gt; are the legs of the right triangle and &lt;em&gt;c&lt;/em&gt; is the hypotenuse.&lt;/p&gt;
&lt;p&gt;Therefore, we can calculate the distance Nadal must run by rearranging the equation to solve for &lt;em&gt;c&lt;/em&gt;:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://files.realpython.com/media/pythagorean_theorem_solve.1176a7b846c3.png&quot; target=&quot;_blank&quot;&gt;&lt;img class=&quot;img-fluid mx-auto d-block w-25&quot; src=&quot;https://files.realpython.com/media/pythagorean_theorem_solve.1176a7b846c3.png&quot; width=&quot;482&quot; height=&quot;101&quot; srcset=&quot;https://robocrop.realpython.net/?url=https%3A//files.realpython.com/media/pythagorean_theorem_solve.1176a7b846c3.png&amp;amp;w=120&amp;amp;sig=8d03f1a0fd30aad550ea41992542ba7324c88166 120w, https://robocrop.realpython.net/?url=https%3A//files.realpython.com/media/pythagorean_theorem_solve.1176a7b846c3.png&amp;amp;w=241&amp;amp;sig=3f9008c13ac2ff534c57692f81aeab1178819346 241w, https://files.realpython.com/media/pythagorean_theorem_solve.1176a7b846c3.png 482w&quot; sizes=&quot;75vw&quot; alt=&quot;Pythagorean Theorem: Solve For C&quot;/&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;You can solve this equation using the Python square root function:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;27&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;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;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;math&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sqrt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&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;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&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;47.43416490252569&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;So, Nadal must run about 47.4 feet (14.5 meters) in order to reach the ball and save the point.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Congratulations! You now know all about the Python square root function.&lt;/p&gt;
&lt;p&gt;You&amp;rsquo;ve covered:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A brief introduction to square roots&lt;/li&gt;
&lt;li&gt;The ins and outs of the Python square root function, &lt;code&gt;sqrt()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;A practical application of &lt;code&gt;sqrt()&lt;/code&gt; using a real-world example&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Knowing how to use &lt;code&gt;sqrt()&lt;/code&gt; is only half the battle. Understanding when to use it is the other. Now, you know both, so go and apply your newfound mastery of the Python square root function!&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 Use the Python or Operator</title>
      <id>https://realpython.com/python-or-operator/</id>
      <link href="https://realpython.com/python-or-operator/"/>
      <updated>2019-07-03T14:00:00+00:00</updated>
      <summary>In this step-by-step tutorial, you&#39;ll learn about how the Python or operator works and how to use it. You&#39;ll get to know its special features and see what kind of programming problems you can solve by using or in Python.</summary>
      <content type="html">
        &lt;p&gt;There are three Boolean operators in Python: &lt;code&gt;and&lt;/code&gt;, &lt;code&gt;or&lt;/code&gt;, and &lt;code&gt;not&lt;/code&gt;. With them, you can test conditions and decide which execution path your programs will take. In this tutorial, you&amp;rsquo;ll learn about the Python &lt;code&gt;or&lt;/code&gt; operator and how to use it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;By the end of this tutorial, you&amp;rsquo;ll have learned:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;How the Python &lt;code&gt;or&lt;/code&gt; operator works&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;How to use the Python &lt;code&gt;or&lt;/code&gt; operator in Boolean and non-Boolean contexts&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;What kind of programming problems you can solve by using &lt;code&gt;or&lt;/code&gt; in Python&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;How to read and better understand other people&amp;rsquo;s code when they use some of the special features of the Python &lt;code&gt;or&lt;/code&gt; operator&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You&amp;rsquo;ll learn how to use the Python &lt;code&gt;or&lt;/code&gt; operator by building some practical examples. Even if you don&amp;rsquo;t really use all the possibilities that the Python &lt;code&gt;or&lt;/code&gt; operator offers, mastering it will allow you to write better code.&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;boolean-logic&quot;&gt;Boolean Logic&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/George_Boole&quot;&gt;George Boole&lt;/a&gt; (1815–1864) developed what is now called &lt;a href=&quot;https://en.wikipedia.org/wiki/Boolean_algebra&quot;&gt;&lt;strong&gt;Boolean algebra&lt;/strong&gt;&lt;/a&gt;, which is the foundation of the digital logic behind computer hardware and programming languages.&lt;/p&gt;
&lt;p&gt;Boolean algebra is built around the &lt;strong&gt;truth value&lt;/strong&gt; of expressions and objects (whether they are &lt;strong&gt;true&lt;/strong&gt; or &lt;strong&gt;false&lt;/strong&gt;) and is based in the Boolean operations &lt;code&gt;AND&lt;/code&gt;, &lt;code&gt;OR&lt;/code&gt;, and &lt;code&gt;NOT&lt;/code&gt;. These operations are implemented through logical or Boolean operators that allow you to create &lt;strong&gt;Boolean expressions&lt;/strong&gt;, which are expressions that evaluate to true or false.&lt;/p&gt;
&lt;p&gt;With the help of Boolean logic, you can evaluate conditions and decide what operations your programs will execute, depending on the truth value of those conditions. This is an important cornerstone in programming and provides you with the tools to decide the execution flow of your programs.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s take a look at some of the basic concepts related to Boolean logic in Python:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Boolean&lt;/strong&gt; is type of value that can be either &lt;code&gt;True&lt;/code&gt; or &lt;code&gt;False&lt;/code&gt;. In Python, the Boolean type is &lt;code&gt;bool&lt;/code&gt;, which is a subtype of &lt;code&gt;int&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Boolean values&lt;/strong&gt;  are the values &lt;code&gt;True&lt;/code&gt; or &lt;code&gt;False&lt;/code&gt; (with a capital &lt;em&gt;T&lt;/em&gt; and &lt;em&gt;F&lt;/em&gt;) in Python.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;A &lt;strong&gt;Boolean variable&lt;/strong&gt; is a variable that can be either &lt;code&gt;True&lt;/code&gt; or &lt;code&gt;False&lt;/code&gt;. Boolean variables are commonly used as &lt;code&gt;flags&lt;/code&gt; to indicate whether specific conditions exist.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;A &lt;strong&gt;Boolean expression&lt;/strong&gt; is an expression that returns either &lt;code&gt;True&lt;/code&gt; or &lt;code&gt;False&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Boolean context&lt;/strong&gt; can be &lt;code&gt;if&lt;/code&gt; conditions and &lt;code&gt;while&lt;/code&gt; loops, where Python expects an expression to evaluate to a Boolean value. You can use virtually any expression or object in a Boolean context, and Python will try to determine its truth value.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Operands&lt;/strong&gt; are the subexpressions or objects involved in an expression (Boolean or not) and connected by an operator.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Boolean or logical operators&lt;/strong&gt;  are &lt;code&gt;AND&lt;/code&gt; (logical &lt;code&gt;AND&lt;/code&gt; or conjunction), &lt;code&gt;OR&lt;/code&gt; (logical &lt;code&gt;OR&lt;/code&gt; or disjunction), and &lt;code&gt;NOT&lt;/code&gt; (logical &lt;code&gt;NOT&lt;/code&gt; or negation). The keywords &lt;strong&gt;&lt;code&gt;and&lt;/code&gt;&lt;/strong&gt;, &lt;strong&gt;&lt;code&gt;or&lt;/code&gt;&lt;/strong&gt;, and &lt;strong&gt;&lt;code&gt;not&lt;/code&gt;&lt;/strong&gt; are the Python operators for these operations.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now that you have a better context on Boolean logic, let&amp;rsquo;s proceed with some more Python-specific topics.&lt;/p&gt;
&lt;h2 id=&quot;the-python-boolean-operators&quot;&gt;The Python Boolean Operators&lt;/h2&gt;
&lt;p&gt;Python has three Boolean operators that are typed out as plain English words: &lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;and&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;or&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;not&lt;/code&gt; &lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;These operators connect Boolean expressions (and objects) to create compound Boolean expressions.&lt;/p&gt;
&lt;p&gt;The Python Boolean operators always take two Boolean expressions or two objects or a combination of them, so they&amp;rsquo;re considered &lt;strong&gt;binary operators&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;In this tutorial, you&amp;rsquo;ll be covering the Python &lt;code&gt;or&lt;/code&gt; operator, which is the operator that implements the logical &lt;code&gt;OR&lt;/code&gt; operation in Python. You&amp;rsquo;ll learn how it works and how to use it.&lt;/p&gt;
&lt;h2 id=&quot;how-the-python-or-operator-works&quot;&gt;How the Python &lt;code&gt;or&lt;/code&gt; Operator Works&lt;/h2&gt;
&lt;p&gt;With the Boolean &lt;code&gt;OR&lt;/code&gt; operator, you can connect two Boolean expressions into one compound expression. At least one subexpressions must be true for the compound expression to be considered true, and it doesn&amp;rsquo;t matter which. If both subexpressions are false, then the expression is false.&lt;/p&gt;
&lt;p&gt;This is the general logic behind the &lt;code&gt;OR&lt;/code&gt; operator. However, the Python &lt;code&gt;or&lt;/code&gt; operator does all this and more, as you&amp;rsquo;ll see in the following sections.&lt;/p&gt;
&lt;h3 id=&quot;using-or-with-boolean-expressions&quot;&gt;Using &lt;code&gt;or&lt;/code&gt; With Boolean Expressions&lt;/h3&gt;
&lt;p&gt;You&amp;rsquo;ll need two subexpressions to create a Boolean expression using the Python &lt;code&gt;or&lt;/code&gt; operator as a connector. The basic syntax for a Boolean expression with &lt;code&gt;or&lt;/code&gt; is as follows:&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;# Syntax for Boolean expression with or in Python&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;exp1&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;exp2&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;If at least one of the subexpressions (&lt;code&gt;exp1&lt;/code&gt; or &lt;code&gt;exp2&lt;/code&gt;) evaluates to &lt;code&gt;True&lt;/code&gt;, then the expression is considered to be &lt;code&gt;True&lt;/code&gt;. If both subexpressions evaluate to &lt;code&gt;False&lt;/code&gt;, then the expression is &lt;code&gt;False&lt;/code&gt;. This definition is called &lt;strong&gt;inclusive or&lt;/strong&gt;, since it allows both possibilities as well as either.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s a summary of the Python &lt;code&gt;or&lt;/code&gt; operator&amp;rsquo;s behavior:&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;Result of &lt;code&gt;exp1&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;Result of &lt;code&gt;exp2&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;Result of &lt;code&gt;exp1 or exp2&lt;/code&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;True&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;True&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;True&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;True&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;False&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;True&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;False&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;True&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;True&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;False&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;False&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;False&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;Table 1.&lt;/em&gt;&lt;/strong&gt; &lt;em&gt;Logical Python &lt;code&gt;or&lt;/code&gt; Operator: Truth Table&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;This table summarizes the resulting truth value of a Boolean expression like &lt;code&gt;exp1 or exp2&lt;/code&gt; depending on the truth values of its subexpressions.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s illustrate the resulting truth values shown in &lt;strong&gt;Table 1&lt;/strong&gt; by coding some practical examples:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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;exp1&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;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&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;exp1&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;exp2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;7&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&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;exp2&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;True&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;exp1&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;exp2&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# Return True, because exp2 is True&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;True&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;exp2&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;exp1&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# Also returns True&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;True&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;exp3&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;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&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;exp1&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;exp3&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# Return False, because both are False&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;False&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In the previous examples, whenever a subexpression is evaluated to &lt;code&gt;True&lt;/code&gt;, the global result is &lt;code&gt;True&lt;/code&gt;. On the other hand, if both subexpressions are evaluated to &lt;code&gt;False&lt;/code&gt;, then the global result is also &lt;code&gt;False&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;using-or-with-common-objects&quot;&gt;Using &lt;code&gt;or&lt;/code&gt; With Common Objects&lt;/h3&gt;
&lt;p&gt;In general, the operands of an expression involving an &lt;code&gt;OR&lt;/code&gt; operation should have Boolean values as shown in &lt;strong&gt;Table 1&lt;/strong&gt; and return a truth value as a result. When it comes to objects, Python is not very strict about that and internally implements a set of rules to decide if an object is considered true or false:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;By default, an object is considered true unless its class defines either a &lt;a href=&quot;https://docs.python.org/3/reference/datamodel.html#object.__bool__&quot;&gt;&lt;code&gt;__bool__()&lt;/code&gt;&lt;/a&gt; method that returns &lt;code&gt;False&lt;/code&gt; or a &lt;a href=&quot;https://docs.python.org/3/reference/datamodel.html#object.__len__&quot;&gt;&lt;code&gt;__len__()&lt;/code&gt;&lt;/a&gt; method that returns zero, when called with the object. Here are most of the built-in objects considered false:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;constants defined to be false: &lt;code&gt;None&lt;/code&gt; and &lt;code&gt;False&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;zero of any numeric type: &lt;code&gt;0&lt;/code&gt;, &lt;code&gt;0.0&lt;/code&gt;, &lt;code&gt;0j&lt;/code&gt;, &lt;code&gt;Decimal(0)&lt;/code&gt;, &lt;code&gt;Fraction(0, 1)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;empty sequences and collections: &lt;code&gt;&#39;&#39;&lt;/code&gt;, &lt;code&gt;()&lt;/code&gt;, &lt;code&gt;[]&lt;/code&gt;, &lt;code&gt;{}&lt;/code&gt;, &lt;code&gt;set()&lt;/code&gt;, &lt;code&gt;range(0)&lt;/code&gt; &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;(&lt;a href=&quot;https://docs.python.org/3/library/stdtypes.html#truth-value-testing&quot;&gt;Source&lt;/a&gt;)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;If the operands involved in an &lt;code&gt;or&lt;/code&gt; operation are objects instead of Boolean expressions, then the Python &lt;code&gt;or&lt;/code&gt; operator returns a true or false object, not the values &lt;code&gt;True&lt;/code&gt; or &lt;code&gt;False&lt;/code&gt; as you could expect. The truth value of this object is determined according to the rules you&amp;rsquo;ve seen before.&lt;/p&gt;
&lt;p&gt;This means that Python doesn&amp;rsquo;t coerce the result of an &lt;code&gt;or&lt;/code&gt; operation to a &lt;code&gt;bool&lt;/code&gt; object. If you&amp;rsquo;re testing two objects using &lt;code&gt;or&lt;/code&gt; in Python, then the operator will return the first object that evaluates to true or the last object in the expression, regardless of its truth value:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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;2&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;
&lt;span class=&quot;go&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;mi&quot;&gt;5&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.0&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;5&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;ow&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;
&lt;span class=&quot;go&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;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{}&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;{}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In the two first examples, the first operands (&lt;code&gt;2&lt;/code&gt; and &lt;code&gt;5&lt;/code&gt;) are true (nonzero), so the Python &lt;code&gt;or&lt;/code&gt; operator always returns the first one.&lt;/p&gt;
&lt;p&gt;In the last two examples, the left operand is false (an empty object). The Python &lt;code&gt;or&lt;/code&gt; operator evaluates both operands and returns the object on the right, which may evaluate to either true or false.&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 you really need to get one of the values &lt;code&gt;True&lt;/code&gt; or &lt;code&gt;False&lt;/code&gt; from a Boolean expression involving objects, then you could use &lt;code&gt;bool(obj)&lt;/code&gt;, which is a built-in function that returns &lt;code&gt;True&lt;/code&gt; or &lt;code&gt;False&lt;/code&gt; depending on the truth value of &lt;code&gt;obj&lt;/code&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;You can summarize the behavior shown in the previous code as follows:&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;Left Object&lt;/th&gt;
&lt;th&gt;Right Object&lt;/th&gt;
&lt;th&gt;Result of &lt;code&gt;x or y&lt;/code&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;x&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;y&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;x&lt;/code&gt;, if it evaluates to true, otherwise &lt;code&gt;y&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;Table 2.&lt;/em&gt;&lt;/strong&gt; &lt;em&gt;Python &lt;code&gt;or&lt;/code&gt; Operator Behavior When Testing Objects Instead of Boolean Expressions&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;In short, the Python &lt;code&gt;or&lt;/code&gt; operator returns the first object that evaluates to true or the last object in the expression, regardless of its truth value.&lt;/p&gt;
&lt;p&gt;You can generalize this behavior by chaining several operations in a single expression 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;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;d&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In this example, the Python &lt;code&gt;or&lt;/code&gt; operator returns the first true operand it finds, or the last one. This is the rule of thumb to memorize how &lt;code&gt;or&lt;/code&gt; works in Python.&lt;/p&gt;
&lt;h3 id=&quot;mixing-boolean-expressions-and-objects&quot;&gt;Mixing Boolean Expressions and Objects&lt;/h3&gt;
&lt;p&gt;You can also combine Boolean expressions and common Python objects in an &lt;code&gt;or&lt;/code&gt; operation. In this case, the Python &lt;code&gt;or&lt;/code&gt; operator will still return the first true operand or the last operand, but the returned value could be &lt;code&gt;True&lt;/code&gt; or &lt;code&gt;False&lt;/code&gt; or the object you&amp;rsquo;re testing:&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;strong&gt;Result of Expression&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Result of Object&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Result of &lt;code&gt;exp or obj&lt;/code&gt;&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;True&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;True&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;True&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;True&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;False&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;True&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;False&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;False&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;obj&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;False&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;True&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;obj&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;Table 3.&lt;/em&gt;&lt;/strong&gt; &lt;em&gt;Python &lt;code&gt;or&lt;/code&gt; Operator Behavior When Testing Objects and Boolean Expressions&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s see how this works with some examples:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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;2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# Case 1&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;True&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;2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# Case 2&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;True&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;5&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# Case 3&lt;/span&gt;
&lt;span class=&quot;go&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;mi&quot;&gt;5&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# Case 4&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;4&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In &lt;strong&gt;Case 1&lt;/strong&gt; and &lt;strong&gt;Case 2&lt;/strong&gt;, the subexpression &lt;code&gt;2 &amp;lt; 4&lt;/code&gt; was evaluated to &lt;code&gt;True&lt;/code&gt;, and the returned value was &lt;code&gt;True&lt;/code&gt;. On the other hand, in &lt;strong&gt;Case 3&lt;/strong&gt; and &lt;strong&gt;Case 4&lt;/strong&gt;, the subexpression &lt;code&gt;5 &amp;gt; 10&lt;/code&gt; was evaluated to &lt;code&gt;False&lt;/code&gt;, so the last operand was returned, and you got an empty list (&lt;code&gt;[]&lt;/code&gt;) and an integer (&lt;code&gt;4&lt;/code&gt;) instead of &lt;code&gt;True&lt;/code&gt; or &lt;code&gt;False&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;As an exercise, you could try to extend &lt;strong&gt;Table 3&lt;/strong&gt; by reversing the order of the expressions in the third column, that is, use &lt;code&gt;obj or exp&lt;/code&gt; and try to predict the results.&lt;/p&gt;
&lt;h3 id=&quot;short-circuit-evaluation&quot;&gt;Short-Circuit Evaluation&lt;/h3&gt;
&lt;p&gt;Python can sometimes determine the truth value of a Boolean expression before it has evaluated all the subexpressions and objects involved. The Python &lt;code&gt;or&lt;/code&gt; operator, for instance, stops evaluating operands as soon as it finds something that&amp;rsquo;s considered true. For example, the following expression is always &lt;code&gt;True&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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;kc&quot;&gt;True&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;True&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;If the first operand in an &lt;code&gt;or&lt;/code&gt; expression evaluates to true, regardless of the value of the second operand (&lt;code&gt;4 &amp;lt; 3&lt;/code&gt; is &lt;code&gt;False&lt;/code&gt;), then the expression is considered to be true, and the second operand is never evaluated. This is called &lt;strong&gt;short-circuit (lazy) evaluation&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s consider another example:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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;true_func&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;s1&quot;&gt;&amp;#39;Running true_func()&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;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;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;false_func&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;s1&quot;&gt;&amp;#39;Running false_func()&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;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;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;true_func&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;n&quot;&gt;false_func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# Case 1&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Running true_func()&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;True&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;false_func&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;n&quot;&gt;true_func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# Case 2&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Running false_func()&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Running true_func()&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;True&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;false_func&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;n&quot;&gt;false_func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# Case 3&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Running false_func()&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Running false_func()&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;true_func&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;n&quot;&gt;true_func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# Case 4&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Running true_func()&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;True&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In &lt;strong&gt;Case 1&lt;/strong&gt;, Python evaluated &lt;code&gt;true_func()&lt;/code&gt;. Since it returns &lt;code&gt;True&lt;/code&gt;, the next operand (&lt;code&gt;false_func()&lt;/code&gt;) is not evaluated. Notice that the phrase &lt;code&gt;Running false_func()&lt;/code&gt; is never printed. Finally, the whole expression is considered &lt;code&gt;True&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Case 2&lt;/strong&gt; evaluates both functions, because the first operand (&lt;code&gt;false_func()&lt;/code&gt;) is &lt;code&gt;False&lt;/code&gt;. Then the operator returns the second result, that is, the value returned by &lt;code&gt;true_func()&lt;/code&gt;, which is &lt;code&gt;True&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Case 3&lt;/strong&gt; evaluates both functions, because both return &lt;code&gt;False&lt;/code&gt;. The operation returns the last function&amp;rsquo;s return value, that is &lt;code&gt;False&lt;/code&gt;, and the expression is considered to be &lt;code&gt;False&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;In &lt;strong&gt;Case 4&lt;/strong&gt;, Python only evaluates the first function, which is &lt;code&gt;True&lt;/code&gt;, and the expression is &lt;code&gt;True&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;In &lt;strong&gt;short-circuit (lazy) evaluation&lt;/strong&gt;, the second operand on a Boolean expression is not evaluated if the value of the expression can be determined from the first operand alone. Python (like other languages) bypasses this second evaluation in favor of performance, because evaluating the second operand would be an unnecessary waste of CPU time.&lt;/p&gt;
&lt;p&gt;Finally, when it comes to performance when you&amp;rsquo;re using the Python &lt;code&gt;or&lt;/code&gt; operator, consider the follow:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;The expressions on the right side of the Python &lt;code&gt;or&lt;/code&gt; operator might call functions that perform substantial or important work, or have side effects that won&amp;rsquo;t happen if the short-circuit rule takes effect.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The condition that is more likely to be true might be the left-most condition. This approach can reduce the execution time of your programs, because this way Python is able to determine if the condition is true just by evaluating the first operand.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;section-recap&quot;&gt;Section Recap&lt;/h3&gt;
&lt;p&gt;You&amp;rsquo;ve learned how the Python &lt;code&gt;or&lt;/code&gt; operator works and have seen some of its main features and behaviors. You now know enough to continue leveling up by learning how to use the operator in solving real-world problems.&lt;/p&gt;
&lt;p&gt;Before that, let&amp;rsquo;s recap some important points about &lt;code&gt;or&lt;/code&gt; in Python:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;It satisfies the general rules that a Boolean &lt;code&gt;OR&lt;/code&gt; operator should follow. If one or both Boolean subexpression are true, then the result is true. Otherwise, if both subexpressions are false, then the result is false.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;It returns objects instead of &lt;code&gt;True&lt;/code&gt; or &lt;code&gt;False&lt;/code&gt; values when it tests Python objects. This means that the expression &lt;code&gt;x or y&lt;/code&gt; returns &lt;code&gt;x&lt;/code&gt; if it&amp;rsquo;s evaluated to true, and otherwise returns &lt;code&gt;y&lt;/code&gt; (regardless of its truth value).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;It follows a predefined set of Python internal rules to determine the truth value of an object.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;It stops evaluating operands as soon as it finds something that&amp;rsquo;s considered true. This is called short-circuit or lazy evaluation.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now it&amp;rsquo;s time to learn where and how you can use this operator with the help of some examples.&lt;/p&gt;
&lt;h2 id=&quot;boolean-contexts&quot;&gt;Boolean Contexts&lt;/h2&gt;
&lt;p&gt;In this section, you&amp;rsquo;ll see some practical examples of how to use the Python &lt;code&gt;or&lt;/code&gt; operator, and learn how to take advantage of its somewhat unusual behavior to write better Python code.&lt;/p&gt;
&lt;p&gt;There are two main situations where you can say you&amp;rsquo;re working in a Boolean context in Python:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://realpython.com/python-conditional-statements/&quot;&gt;&lt;code&gt;if&lt;/code&gt; statements&lt;/a&gt;:&lt;/strong&gt; conditional execution&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://realpython.com/python-while-loop/&quot;&gt;&lt;code&gt;while&lt;/code&gt; loops&lt;/a&gt;:&lt;/strong&gt; conditional repetition&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;With an &lt;code&gt;if&lt;/code&gt; statement, you can decide your programs&amp;rsquo; path of execution depending on the truth value of some conditions.&lt;/p&gt;
&lt;p&gt;On the other hand, &lt;code&gt;while&lt;/code&gt; loops allow you to repeat a piece of code as long as a given condition remains true.&lt;/p&gt;
&lt;p&gt;These two structures are part of what you&amp;rsquo;d call &lt;strong&gt;control flow statements&lt;/strong&gt;. They help you decide your programs&amp;rsquo; execution path.&lt;/p&gt;
&lt;p&gt;You can use the Python &lt;code&gt;or&lt;/code&gt; operator to build Boolean expressions suitable for use with both &lt;code&gt;if&lt;/code&gt; statement and &lt;code&gt;while&lt;/code&gt; loops, as you&amp;rsquo;ll see in the next two sections.&lt;/p&gt;
&lt;h3 id=&quot;if-statements&quot;&gt;&lt;code&gt;if&lt;/code&gt; Statements&lt;/h3&gt;
&lt;p&gt;Let&amp;rsquo;s say you want to make sure that one of two conditions (or both) is true before you choose a certain
path of execution. In this case, you can use the Python &lt;code&gt;or&lt;/code&gt; operator to connect the conditions in one expression, and use that expression in an &lt;code&gt;if&lt;/code&gt; statement.&lt;/p&gt;
&lt;p&gt;Suppose you need to get a confirmation from the user to run some actions depending on the user&amp;rsquo;s answer:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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;answer&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;ans&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;Do you...? (yes/no): &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;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ans&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lower&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;yes&amp;#39;&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ans&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lower&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;y&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;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;Positive answer: &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{ans}&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;gp&quot;&gt;... &lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;elif&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ans&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lower&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;no&amp;#39;&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ans&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lower&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;n&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;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;Negative answer: &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{ans}&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;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;answer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Do you...? (yes/no): y&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Positive answer: y&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;answer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Do you...? (yes/no): n&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Negative answer: n&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Here, you get the user&amp;rsquo;s input and assign it to &lt;code&gt;ans&lt;/code&gt;. Then, the &lt;code&gt;if&lt;/code&gt; statement starts checking the conditions from left to right. If at least one of them is evaluated to true, then it executes the &lt;code&gt;if&lt;/code&gt; code block. The &lt;code&gt;elif&lt;/code&gt; statement does the same.&lt;/p&gt;
&lt;p&gt;In the first call to &lt;code&gt;answer()&lt;/code&gt;, the user&amp;rsquo;s input was &lt;code&gt;y&lt;/code&gt;, which satisfied the first condition, and the &lt;code&gt;if&lt;/code&gt; code block was executed. In the second call, the user&amp;rsquo;s input (&lt;code&gt;n&lt;/code&gt;) satisfied the second condition, so the &lt;code&gt;elif&lt;/code&gt; code block ran. If the user input doesn&amp;rsquo;t satisfy any condition, then no code block is executed.&lt;/p&gt;
&lt;p&gt;Another example could be when you&amp;rsquo;re trying to determine whether a number is outside a range. In this case, it&amp;rsquo;s also possible to use the Python &lt;code&gt;or&lt;/code&gt; operator. The following code tests whether &lt;code&gt;x&lt;/code&gt; is outside the range of &lt;code&gt;20&lt;/code&gt; through &lt;code&gt;40&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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;my_range&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;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;20&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;40&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;s1&quot;&gt;&amp;#39;Outside&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;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;Inside&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;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;my_range&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;go&quot;&gt;Inside&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;my_range&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;18&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Outside&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;When you call &lt;code&gt;my_range()&lt;/code&gt; with &lt;code&gt;x=25&lt;/code&gt;, the &lt;code&gt;if&lt;/code&gt; statement tests &lt;code&gt;25 &amp;lt; 20&lt;/code&gt;, which is &lt;code&gt;False&lt;/code&gt;. Then it tests &lt;code&gt;x &amp;gt; 40&lt;/code&gt;, which is also &lt;code&gt;False&lt;/code&gt;. The final result is &lt;code&gt;False&lt;/code&gt;, so the &lt;code&gt;else&lt;/code&gt; block was executed.&lt;/p&gt;
&lt;p&gt;On the other hand, &lt;code&gt;18 &amp;lt; 20&lt;/code&gt; is evaluated to &lt;code&gt;True&lt;/code&gt;. Then the Python &lt;code&gt;or&lt;/code&gt; operator makes short-circuit evaluation, and the condition is considered to be &lt;code&gt;True&lt;/code&gt;. The main block is executed, and the value is outside the range.&lt;/p&gt;
&lt;h3 id=&quot;while-loops&quot;&gt;&lt;code&gt;while&lt;/code&gt; Loops&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;while&lt;/code&gt; loops are another example of Boolean context where you can use the Python &lt;code&gt;or&lt;/code&gt; operator. By using &lt;code&gt;or&lt;/code&gt; in the loop&amp;rsquo;s header, you can test several conditions and run the body until all the conditions evaluate to false.&lt;/p&gt;
&lt;p&gt;Suppose you need to measure the operating temperature of some industrial equipment until it gets into a range of 100 ºF to 140 ºF. To do so, you can use a &lt;code&gt;while&lt;/code&gt; loop:&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;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;n&quot;&gt;temp&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;measure_temp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# Initial temperature measurement&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;temp&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;temp&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;140&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;Temperature outside the recommended range&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;New Temperature measure in 30 seconds&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&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;30&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;Measuring Temperature...&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;temp&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;measure_temp&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;The new Temperature is &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{temp}&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt; ºF&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This is a toy example almost in pseudo code, but it illustrates the idea. Here, the &lt;code&gt;while&lt;/code&gt; loop is running until &lt;code&gt;temp&lt;/code&gt; is between 100 ºF and 140 ºF. If the temperature value is outside the range, then the loop&amp;rsquo;s body is run, and you&amp;rsquo;ll be measuring the temperature again. Once &lt;code&gt;measure_temp()&lt;/code&gt; returns a value between 100 ºF and 140 ºF, the loop finishes. The temperature measurement is taken every 30 seconds by &lt;a href=&quot;https://realpython.com/python-time-module/#suspending-execution&quot;&gt;using &lt;code&gt;sleep(30)&lt;/code&gt;&lt;/a&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; In the previous code example, you used Python&amp;rsquo;s f-strings for string formatting, if you want to dive deeper into f-strings, then you can take a look at  &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;h2 id=&quot;non-boolean-contexts&quot;&gt;Non-Boolean Contexts&lt;/h2&gt;
&lt;p&gt;You can take advantage of the special features of the Python &lt;code&gt;or&lt;/code&gt; operator out of Boolean contexts. The rule of thumb is still that the result of your Boolean expressions is the first true operand or the last in the line.&lt;/p&gt;
&lt;p&gt;Notice that the logical operators (&lt;code&gt;or&lt;/code&gt; included) are evaluated before the assignment operator (&lt;code&gt;=&lt;/code&gt;), so you can assign the result of a Boolean expression to a variable in the same way you do with a common expression:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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;a&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;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;b&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;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;var1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&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;var1&lt;/span&gt;
&lt;span class=&quot;go&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;a&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;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;b&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;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;var2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&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;var2&lt;/span&gt;
&lt;span class=&quot;go&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;a&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;b&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;var3&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&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;var3&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;{}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Here, the &lt;code&gt;or&lt;/code&gt; operator works as expected, returning the first true operand or the last operand if both are evaluated to false.&lt;/p&gt;
&lt;p&gt;You can take advantage of this somewhat special behavior of &lt;code&gt;or&lt;/code&gt; in Python to implement a Pythonic solution to some quite common programming problems. Let&amp;rsquo;s take a look at some real-world examples.&lt;/p&gt;
&lt;h3 id=&quot;default-values-for-variables&quot;&gt;Default Values for Variables&lt;/h3&gt;
&lt;p&gt;One common way to use the Python &lt;code&gt;or&lt;/code&gt; operator is to select an object from a set of objects according to its truth value. You can do this by using an assignment statement:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;None&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Here, you assigned to &lt;code&gt;x&lt;/code&gt; the first true object in the expression. If all objects (&lt;code&gt;a&lt;/code&gt;  and &lt;code&gt;b&lt;/code&gt; in this case) are false objects, then the Python &lt;code&gt;or&lt;/code&gt; operator returns &lt;code&gt;None&lt;/code&gt;, which is the last operand. This works because the &lt;code&gt;or&lt;/code&gt; operator returns one of its operands depending on their truth value.&lt;/p&gt;
&lt;p&gt;You can also use this feature to assign a default value to your variables. The following example sets &lt;code&gt;x&lt;/code&gt; to &lt;code&gt;a&lt;/code&gt; if &lt;code&gt;a&lt;/code&gt; is true, and to &lt;code&gt;default&lt;/code&gt; otherwise:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;default&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In the previous code, you assign &lt;code&gt;a&lt;/code&gt; to &lt;code&gt;x&lt;/code&gt; only if &lt;code&gt;a&lt;/code&gt; is evaluated to true. Otherwise, &lt;code&gt;x&lt;/code&gt; is assigned &lt;code&gt;default&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;default-return-values&quot;&gt;Default &lt;code&gt;return&lt;/code&gt; Values&lt;/h3&gt;
&lt;p&gt;You can manipulate the &lt;code&gt;return&lt;/code&gt; value of some built-in functions at call time. Functions like &lt;a href=&quot;https://docs.python.org/3/library/functions.html#max&quot;&gt;&lt;code&gt;max()&lt;/code&gt;&lt;/a&gt; and &lt;a href=&quot;https://docs.python.org/3/library/functions.html#min&quot;&gt;&lt;code&gt;min()&lt;/code&gt;&lt;/a&gt;, which take an iterable as an argument and return a single value, could be your perfect candidate for this sort of hack. &lt;/p&gt;
&lt;p&gt;If you supply an empty iterable to &lt;code&gt;max()&lt;/code&gt; or &lt;code&gt;min()&lt;/code&gt;, then you&amp;rsquo;ll get a &lt;code&gt;ValueError&lt;/code&gt;. However, you can modify this behavior by using the Python &lt;code&gt;or&lt;/code&gt; operator. Let&amp;rsquo;s take a look at the following code:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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;lst&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;c1&quot;&gt;# Empty list to test max() and min()&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;max&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lst&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;gt&quot;&gt;Traceback (most recent call last):&lt;/span&gt;
  File &lt;span class=&quot;nb&quot;&gt;&amp;quot;&amp;lt;input&amp;gt;&amp;quot;&lt;/span&gt;, line &lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;, in &lt;span class=&quot;n&quot;&gt;&amp;lt;module&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;max&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lst&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;gr&quot;&gt;ValueError&lt;/span&gt;: &lt;span class=&quot;n&quot;&gt;max() arg is an empty sequence&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;min&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lst&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;gt&quot;&gt;Traceback (most recent call last):&lt;/span&gt;
  File &lt;span class=&quot;nb&quot;&gt;&amp;quot;&amp;lt;input&amp;gt;&amp;quot;&lt;/span&gt;, line &lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;, in &lt;span class=&quot;n&quot;&gt;&amp;lt;module&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;min&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lst&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;gr&quot;&gt;ValueError&lt;/span&gt;: &lt;span class=&quot;n&quot;&gt;min() arg is an empty sequence&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;# Use Python or operator to modify this behavior&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;max&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lst&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;or&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;c1&quot;&gt;# Return 0&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;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;min&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lst&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;or&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;c1&quot;&gt;# Return 0&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;0&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The default behavior of &lt;code&gt;max()&lt;/code&gt; and &lt;code&gt;min()&lt;/code&gt; is to raise a &lt;code&gt;ValueError&lt;/code&gt; if you call them with an empty iterable. However, by using the Python &lt;code&gt;or&lt;/code&gt; operator, you supply a default &lt;code&gt;return&lt;/code&gt; value for these functions and override their default behavior.&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; In the previous code example, you saw how Python raises exceptions when some problems occur. If you want to know more about exceptions in Python, then you can take a look &lt;a href=&quot;https://realpython.com/courses/introduction-python-exceptions/&quot;&gt;Introduction to Python Exceptions&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;h3 id=&quot;mutable-default-arguments&quot;&gt;Mutable Default Arguments&lt;/h3&gt;
&lt;p&gt;A common problem beginner Python programmers face is to try to use mutable objects as default arguments to functions.&lt;/p&gt;
&lt;p&gt;Mutable values for default arguments can retain state between calls. This is often unexpected. It happens because default argument values are evaluated and saved only once, that is, when the &lt;code&gt;def&lt;/code&gt; statement is run, not each time the resulting function is called. That&amp;rsquo;s why you need to be careful about changing mutable defaults inside functions.&lt;/p&gt;
&lt;p&gt;Consider the following example:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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;mutable_default&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lst&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;c1&quot;&gt;# Try to use a mutable value as default&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;... &lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;lst&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;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# Change same object each time&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;lst&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;mutable_default&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lst&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;3&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;c1&quot;&gt;# Default not used&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;[3, 2, 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;mutable_default&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# Default used&lt;/span&gt;
&lt;span class=&quot;go&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;mutable_default&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# Default grows on each call&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;[1, 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;mutable_default&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;[1, 1, 1]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Here, every call to &lt;code&gt;mutable_default()&lt;/code&gt; appends &lt;code&gt;1&lt;/code&gt; to the end of &lt;code&gt;lst&lt;/code&gt;, because &lt;code&gt;lst&lt;/code&gt; holds a reference to the same object (the default &lt;code&gt;[]&lt;/code&gt;). You don&amp;rsquo;t get a new &lt;code&gt;list&lt;/code&gt; every time the function is called as you would expect.&lt;/p&gt;
&lt;p&gt;If that&amp;rsquo;s not the behavior you want, then the traditional (and safest) solution is to move the default to the body of the function:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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;mutable_default&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lst&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;c1&quot;&gt;# Use None as formal default&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;lst&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;is&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;gp&quot;&gt;... &lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;lst&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;c1&quot;&gt;# Default used? Then lst gets a new empty list.&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;... &lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;lst&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;mi&quot;&gt;1&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;lst&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;mutable_default&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lst&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;3&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;c1&quot;&gt;# Default not used&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;[3, 2, 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;mutable_default&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# Default used&lt;/span&gt;
&lt;span class=&quot;go&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;mutable_default&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;[1]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;With this implementation, you are ensuring that &lt;code&gt;lst&lt;/code&gt; is set to an empty &lt;code&gt;list&lt;/code&gt; every time you call &lt;code&gt;mutable_default()&lt;/code&gt; with no argument, relying in the default value for &lt;code&gt;lst&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;if&lt;/code&gt; statement in this example could almost be replaced by the assignment &lt;code&gt;lst = lst or []&lt;/code&gt;. This way, if no argument is passed in to the function, then &lt;code&gt;lst&lt;/code&gt; would default to &lt;code&gt;None&lt;/code&gt; and the Python &lt;code&gt;or&lt;/code&gt; operator would return the empty list on the right:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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;mutable_default&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lst&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;c1&quot;&gt;# Use None as formal default&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;... &lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;lst&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lst&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# Default used? Then lst gets an empty list.&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;... &lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;lst&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;mi&quot;&gt;1&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;lst&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;mutable_default&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lst&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;3&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;c1&quot;&gt;# Default not used&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;[3, 2, 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;mutable_default&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# Default used&lt;/span&gt;
&lt;span class=&quot;go&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;mutable_default&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;[1]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;However, this isn&amp;rsquo;t exactly the same. For example, if an empty &lt;code&gt;list&lt;/code&gt; is passed in, then the &lt;code&gt;or&lt;/code&gt; operation would cause the function to modify and print a newly created &lt;code&gt;list&lt;/code&gt;, rather than modifying and printing the originally passed-in &lt;code&gt;list&lt;/code&gt; like the &lt;code&gt;if&lt;/code&gt; version would do.&lt;/p&gt;
&lt;p&gt;If you are pretty sure that you&amp;rsquo;ll only be using non-empty &lt;code&gt;list&lt;/code&gt; objects, then you can use this approach. Otherwise, stick to the &lt;code&gt;if&lt;/code&gt; version.&lt;/p&gt;
&lt;h3 id=&quot;zero-division&quot;&gt;Zero Division&lt;/h3&gt;
&lt;p&gt;Zero division can be a common problem when you&amp;rsquo;re dealing with numeric calculations. To avoid this problem, it&amp;rsquo;s likely that you end up checking if the denominator is equal to &lt;code&gt;0&lt;/code&gt; or not by using an &lt;code&gt;if&lt;/code&gt; statement.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s take a look at an example:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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;divide&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&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;ow&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&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;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&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;divide&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;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;5.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;divide&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;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;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;n&quot;&gt;divide&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;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Here, you tested if the denominator (&lt;code&gt;b&lt;/code&gt;) was not equal to &lt;code&gt;0&lt;/code&gt;, and then you returned the result of the division operation. If &lt;code&gt;b == 0&lt;/code&gt; is evaluated to &lt;code&gt;True&lt;/code&gt;, then &lt;code&gt;divide()&lt;/code&gt; implicitly returns &lt;code&gt;None&lt;/code&gt;. Let&amp;rsquo;s see how to get a similar result, but this time using the Python &lt;code&gt;or&lt;/code&gt; operator:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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;divide&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&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;b&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;or&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&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;divide&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;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;5.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;divide&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;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;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;n&quot;&gt;divide&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;0&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;In this case, the Python &lt;code&gt;or&lt;/code&gt; operator evaluates the first subexpression (&lt;code&gt;b == 0&lt;/code&gt;). Only if this subexpression is &lt;code&gt;False&lt;/code&gt;, the second subexpression (&lt;code&gt;a / b&lt;/code&gt;) is evaluated, and the final result will be the division of &lt;code&gt;a&lt;/code&gt; and &lt;code&gt;b&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The difference with the previous example is that, if &lt;code&gt;b == 0&lt;/code&gt; is evaluated to &lt;code&gt;True&lt;/code&gt;, then &lt;code&gt;divide()&lt;/code&gt; returns &lt;code&gt;True&lt;/code&gt; instead of the implicit &lt;code&gt;None&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;multiple-expressions-in-lambda&quot;&gt;Multiple Expressions in &lt;code&gt;lambda&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;Python provides &lt;a href=&quot;https://realpython.com/python-lambda/&quot;&gt;&lt;code&gt;lambda&lt;/code&gt; expressions&lt;/a&gt;, which allow you to create simple anonymous functions. The expression &lt;code&gt;lambda parameters: expression&lt;/code&gt; yields a function object. This kind of function may be useful if you want to define simple callback and key functions.&lt;/p&gt;
&lt;p&gt;The most common pattern for you to write a &lt;code&gt;lambda&lt;/code&gt; function is to use a single &lt;code&gt;expression&lt;/code&gt; as a return value. However, you can change this and let &lt;code&gt;lambda&lt;/code&gt; execute several expressions by using the Python &lt;code&gt;or&lt;/code&gt; operator:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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;lambda_func&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;hello&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;world&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;hello&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;s1&quot;&gt;&amp;#39; &amp;#39;&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;nb&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;world&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;lambda_func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;Hello&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;World!&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Hello World!&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;With this example, you&amp;rsquo;ve forced &lt;code&gt;lambda&lt;/code&gt; to run two expressions (&lt;code&gt;print(hello, end=&#39; &#39;)&lt;/code&gt; and &lt;code&gt;print(world)&lt;/code&gt;). But how does this code work?  Well, here &lt;code&gt;lambda&lt;/code&gt; runs a Boolean expression where two functions are executed.&lt;/p&gt;
&lt;p&gt;When &lt;code&gt;or&lt;/code&gt; evaluates the first function, it receives &lt;code&gt;None&lt;/code&gt;, which is the implicit return value for &lt;code&gt;print()&lt;/code&gt;. Since &lt;code&gt;None&lt;/code&gt; is considered to be false, &lt;code&gt;or&lt;/code&gt; continues to evaluate its second operand, and finally returns it as a result for the Boolean expression.&lt;/p&gt;
&lt;p&gt;In this case, the value returned by the Boolean expression is also the value returned by &lt;code&gt;lambda&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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;result&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lambda_func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;Hello&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;World!&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Hello World!&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;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;None&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Here, &lt;code&gt;result&lt;/code&gt; holds a reference to the value returned by &lt;code&gt;lambda&lt;/code&gt;, which is the same value returned by the Boolean expression.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;You now know how the Python &lt;code&gt;or&lt;/code&gt; operator works as well as how to use it for solving some common programming problems in Python. &lt;/p&gt;
&lt;p&gt;Now that you know the basics of the Python &lt;code&gt;or&lt;/code&gt; operator, you&amp;rsquo;ll be able to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Use the Python &lt;code&gt;or&lt;/code&gt; operator in Boolean and non-Boolean contexts&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Solve several kind of programming problems by effectively using the Python &lt;code&gt;or&lt;/code&gt; operator&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Write better and more Pythonic code by taking advantage of the somewhat special features of &lt;code&gt;or&lt;/code&gt; in Python&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Read and better understand other people&amp;rsquo;s code when they make use of the Python &lt;code&gt;or&lt;/code&gt; operator&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In addition, you&amp;rsquo;ve learned a little bit about Boolean logic, as well as some of its main concepts in Python.&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>Functional Programming in Python</title>
      <id>https://realpython.com/courses/functional-programming-python/</id>
      <link href="https://realpython.com/courses/functional-programming-python/"/>
      <updated>2019-07-02T14:00:00+00:00</updated>
      <summary>In this course, you&#39;ll learn how to approach functional programming in Python. You&#39;ll cover what functional programming is, how you can use immutable data structures to represent your data, as well as how to use filter(), map(), and reduce().</summary>
      <content type="html">
        &lt;p&gt;In this course, you&amp;rsquo;ll learn how to approach functional programming in Python. You&amp;rsquo;ll start with the absolute basics of Functional Programming (FP). After that, you&amp;rsquo;ll see hands-on examples for common FP patterns available, like using immutable data structures and the &lt;code&gt;filter()&lt;/code&gt;, &lt;code&gt;map()&lt;/code&gt;, and &lt;code&gt;reduce()&lt;/code&gt; functions. You&amp;rsquo;ll end the course with actionable tips for parallelizing your code to make it run faster.&lt;/p&gt;
&lt;p&gt;You&amp;rsquo;ll cover:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;What functional programming is&lt;/li&gt;
&lt;li&gt;How you can use immutable data structures to represent your data&lt;/li&gt;
&lt;li&gt;How to use &lt;code&gt;filter()&lt;/code&gt;, &lt;code&gt;map()&lt;/code&gt;, and &lt;code&gt;reduce()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;How to do parallel processing with &lt;code&gt;multiprocessing&lt;/code&gt; and &lt;code&gt;concurrent.futures&lt;/code&gt;&lt;/li&gt;
&lt;/ol&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 Use Redis With Python</title>
      <id>https://realpython.com/python-redis/</id>
      <link href="https://realpython.com/python-redis/"/>
      <updated>2019-07-01T14:00:00+00:00</updated>
      <summary>In this step-by-step tutorial, you&#39;ll cover how to use both Redis and its Python client library. You&#39;ll learn a bite-sized slice of Redis itself and master the redis-py client library.</summary>
      <content type="html">
        &lt;p&gt;In this tutorial, you&amp;rsquo;ll learn how to use Python with Redis (pronounced &lt;a href=&quot;https://redis.io/topics/faq&quot;&gt;RED-iss&lt;/a&gt;, or maybe &lt;a href=&quot;https://groups.google.com/forum/#!topic/redis-db/MtwjZC5gCeE&quot;&gt;REE-diss&lt;/a&gt; or &lt;a href=&quot;https://en.wikipedia.org/wiki/Talk:Redis#Pronounciation&quot;&gt;Red-DEES&lt;/a&gt;, depending on who you ask), which is a lightning fast in-memory key-value store that can be used for anything from A to Z.  Here&amp;rsquo;s what &lt;em&gt;Seven Databases in Seven Weeks&lt;/em&gt;, a popular book on databases, has to say about Redis:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;It&amp;rsquo;s not simply easy to use; it&amp;rsquo;s a joy. If an API is UX for programmers, then Redis should be in the Museum of Modern Art alongside the Mac Cube.&lt;/p&gt;
&lt;p&gt;&amp;hellip;&lt;/p&gt;
&lt;p&gt;And when it comes to speed, Redis is hard to beat. Reads are fast, and writes are even faster, handling upwards of 100,000 &lt;code&gt;SET&lt;/code&gt; operations per second by some benchmarks. (&lt;a href=&quot;https://realpython.com/asins/1680502530/&quot;&gt;Source&lt;/a&gt;)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Intrigued?  This tutorial is built for the Python programmer who may have zero to little Redis experience.  We&amp;rsquo;ll tackle two tools at once and introduce both Redis itself as well as one of its Python client libraries, &lt;a href=&quot;https://github.com/andymccurdy/redis-py&quot;&gt;&lt;code&gt;redis-py&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;redis-py&lt;/code&gt; (which you import as just &lt;code&gt;redis&lt;/code&gt;) is one of many Python clients for Redis, but it has the distinction of being billed as &lt;a href=&quot;https://redis.io/clients#python&quot;&gt;&amp;ldquo;currently the way to go for Python&amp;rdquo;&lt;/a&gt; by the Redis developers themselves.  It lets you call Redis commands from Python, and get back familiar Python objects in return.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;In this tutorial, you&amp;rsquo;ll cover&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Installing Redis from source and understanding the purpose of the resulting binaries&lt;/li&gt;
&lt;li&gt;Learning a bite-size slice of Redis itself, including its syntax, protocol, and design&lt;/li&gt;
&lt;li&gt;Mastering &lt;code&gt;redis-py&lt;/code&gt; while also seeing glimpses of how it implements Redis&amp;rsquo; protocol&lt;/li&gt;
&lt;li&gt;Setting up and communicating with an Amazon ElastiCache Redis server instance&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-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;installing-redis-from-source&quot;&gt;Installing Redis From Source&lt;/h2&gt;
&lt;p&gt;As my great-great-grandfather said, nothing builds grit like installing from source.  This section will walk you through downloading, making, and installing Redis.  I promise that this won&amp;rsquo;t hurt one bit!&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 section is oriented towards installation on Mac OS X or Linux.  If you&amp;rsquo;re using Windows, there is a Microsoft &lt;a href=&quot;https://github.com/MicrosoftArchive/redis&quot;&gt;fork&lt;/a&gt; of Redis that can be installed as a Windows Service.  Suffice it to say that Redis as a program lives most comfortably on a Linux box and that setup and use on Windows may be finicky.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;First, download the Redis source code as a tarball:&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;nv&quot;&gt;redisurl&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;http://download.redis.io/redis-stable.tar.gz&amp;quot;&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; curl -s -o redis-stable.tar.gz &lt;span class=&quot;nv&quot;&gt;$redisurl&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Next, switch over to &lt;code&gt;root&lt;/code&gt; and extract the archive&amp;rsquo;s source code to &lt;code&gt;/usr/local/lib/&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; sudo su root
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; mkdir -p /usr/local/lib/
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; chmod a+w /usr/local/lib/
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; tar -C /usr/local/lib/ -xzf redis-stable.tar.gz
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Optionally, you can now remove the archive itself:&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 redis-stable.tar.gz
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This will leave you with a source code repository at &lt;code&gt;/usr/local/lib/redis-stable/&lt;/code&gt;.  Redis is written in C, so you&amp;rsquo;ll need to compile, link, and install with the &lt;a href=&quot;https://www.gnu.org/software/make/&quot;&gt;&lt;code&gt;make&lt;/code&gt;&lt;/a&gt; utility:&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;cd&lt;/span&gt; /usr/local/lib/redis-stable/
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; make &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; make install
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Using &lt;code&gt;make install&lt;/code&gt; does two actions:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;The first &lt;code&gt;make&lt;/code&gt; command compiles and links the source code.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The &lt;code&gt;make install&lt;/code&gt; part takes the binaries and copies them to &lt;code&gt;/usr/local/bin/&lt;/code&gt; so that you can run them from anywhere (assuming that &lt;code&gt;/usr/local/bin/&lt;/code&gt; is in &lt;code&gt;PATH&lt;/code&gt;).&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Here are all the steps so far:&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;nv&quot;&gt;redisurl&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;http://download.redis.io/redis-stable.tar.gz&amp;quot;&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; curl -s -o redis-stable.tar.gz &lt;span class=&quot;nv&quot;&gt;$redisurl&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; sudo su root
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; mkdir -p /usr/local/lib/
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; chmod a+w /usr/local/lib/
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; tar -C /usr/local/lib/ -xzf redis-stable.tar.gz
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; rm redis-stable.tar.gz
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; /usr/local/lib/redis-stable/
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; make &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; make install
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;At this point, take a moment to confirm that Redis is in your &lt;code&gt;PATH&lt;/code&gt; and check its version:&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; redis-cli --version
&lt;span class=&quot;go&quot;&gt;redis-cli 5.0.3&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;If your shell can&amp;rsquo;t find &lt;code&gt;redis-cli&lt;/code&gt;, check to make sure that &lt;code&gt;/usr/local/bin/&lt;/code&gt; is on your &lt;code&gt;PATH&lt;/code&gt; environment variable, and add it if not.&lt;/p&gt;
&lt;p&gt;In addition to &lt;code&gt;redis-cli&lt;/code&gt;, &lt;code&gt;make install&lt;/code&gt; actually leads to a handful of different executable files (and one symlink) being placed at &lt;code&gt;/usr/local/bin/&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; &lt;span class=&quot;c1&quot;&gt;# A snapshot of executables that come bundled with Redis&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; ls -hFG /usr/local/bin/redis-* &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; sort
&lt;span class=&quot;go&quot;&gt;/usr/local/bin/redis-benchmark*&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;/usr/local/bin/redis-check-aof*&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;/usr/local/bin/redis-check-rdb*&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;/usr/local/bin/redis-cli*&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;/usr/local/bin/redis-sentinel@&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;/usr/local/bin/redis-server*&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;While all of these have some intended use, the two you&amp;rsquo;ll probably care about most are &lt;code&gt;redis-cli&lt;/code&gt; and &lt;code&gt;redis-server&lt;/code&gt;, which we&amp;rsquo;ll outline shortly.  But before we get to that, setting up some baseline configuration is in order.&lt;/p&gt;
&lt;h2 id=&quot;configuring-redis&quot;&gt;Configuring Redis&lt;/h2&gt;
&lt;p&gt;Redis is highly configurable.  While it runs fine out of the box, let&amp;rsquo;s take a minute to set some bare-bones configuration options that relate to database persistence and basic security:&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; sudo su root
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; mkdir -p /etc/redis/
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; touch /etc/redis/6379.conf
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now, write the following to &lt;code&gt;/etc/redis/6379.conf&lt;/code&gt;.  We&amp;rsquo;ll cover what most of these mean gradually throughout the tutorial:&lt;/p&gt;
&lt;div class=&quot;highlight text&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;# /etc/redis/6379.conf

port              6379
daemonize         yes
save              60 1
bind              127.0.0.1
tcp-keepalive     300
dbfilename        dump.rdb
dir               ./
rdbcompression    yes
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Redis configuration is self-documenting, with the &lt;a href=&quot;http://download.redis.io/redis-stable/redis.conf&quot;&gt;sample &lt;code&gt;redis.conf&lt;/code&gt; file&lt;/a&gt; located in the Redis source for your reading pleasure. If you&amp;rsquo;re using Redis in a production system, it pays to block out all distractions and take the time to read this sample file in full to familiarize yourself with the ins and outs of Redis and fine-tune your setup.&lt;/p&gt;
&lt;p&gt;Some tutorials, including parts of Redis&amp;rsquo; documentation, may also suggest running the Shell script &lt;code&gt;install_server.sh&lt;/code&gt; located in &lt;a href=&quot;http://download.redis.io/redis-stable/utils/install_server.sh&quot;&gt;&lt;code&gt;redis/utils/install_server.sh&lt;/code&gt;&lt;/a&gt;.  You&amp;rsquo;re by all means welcome to run this as a more comprehensive alternative to the above, but take note of a few finer points about &lt;code&gt;install_server.sh&lt;/code&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It will not work on Mac OS X&amp;mdash;only Debian and Ubuntu Linux.&lt;/li&gt;
&lt;li&gt;It will inject a fuller set of configuration options into &lt;code&gt;/etc/redis/6379.conf&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;It will write a System V &lt;a href=&quot;https://bash.cyberciti.biz/guide//etc/init.d&quot;&gt;&lt;code&gt;init&lt;/code&gt; script&lt;/a&gt; to &lt;code&gt;/etc/init.d/redis_6379&lt;/code&gt; that will let you do &lt;code&gt;sudo service redis_6379 start&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The Redis quickstart guide also contains a section on a &lt;a href=&quot;https://redis.io/topics/quickstart#installing-redis-more-properly&quot;&gt;more proper Redis setup&lt;/a&gt;, but the configuration options above should be totally sufficient for this tutorial and getting started.&lt;/p&gt;
&lt;div class=&quot;alert alert-primary&quot; role=&quot;alert&quot;&gt;
&lt;p&gt;&lt;strong&gt;Security Note:&lt;/strong&gt; A few years back, the author of Redis pointed out security vulnerabilities in earlier versions of Redis if no configuration was set.  Redis 3.2 (the current version 5.0.3 as of March 2019) made steps to prevent this intrusion, setting the &lt;code&gt;protected-mode&lt;/code&gt; option to &lt;code&gt;yes&lt;/code&gt; by default.&lt;/p&gt;
&lt;p&gt;We explicitly set &lt;code&gt;bind 127.0.0.1&lt;/code&gt; to let Redis listen for connections only from the localhost interface, although you would need to expand this whitelist in a real production server.  The point of &lt;code&gt;protected-mode&lt;/code&gt; is as a safeguard that will mimic this bind-to-localhost behavior if you don&amp;rsquo;t otherwise specify anything under the &lt;code&gt;bind&lt;/code&gt; option.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;With that squared away, we can now dig into using Redis itself.&lt;/p&gt;
&lt;h2 id=&quot;ten-or-so-minutes-to-redis&quot;&gt;Ten or So Minutes to Redis&lt;/h2&gt;
&lt;p&gt;This section will provide you with just enough knowledge of Redis to be dangerous, outlining its design and basic usage.&lt;/p&gt;
&lt;h3 id=&quot;getting-started&quot;&gt;Getting Started&lt;/h3&gt;
&lt;p&gt;Redis has a &lt;strong&gt;client-server architecture&lt;/strong&gt; and uses a &lt;strong&gt;request-response model&lt;/strong&gt;.  This means that you (the client) connect to a Redis server through TCP connection, on port 6379 by default.  You request some action (like some form of reading, writing, getting, setting, or updating), and the server &lt;em&gt;serves&lt;/em&gt; you back a response.&lt;/p&gt;
&lt;p&gt;There can be many clients talking to the same server, which is really what Redis or any client-server application is all about.  Each client does a (typically blocking) read on a socket waiting for the server response.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;cli&lt;/code&gt; in &lt;code&gt;redis-cli&lt;/code&gt; stands for &lt;strong&gt;command line interface&lt;/strong&gt;, and the &lt;code&gt;server&lt;/code&gt; in &lt;code&gt;redis-server&lt;/code&gt; is for, well, running a server.  In the same way that you would run &lt;code&gt;python&lt;/code&gt; at the command line, you can run &lt;code&gt;redis-cli&lt;/code&gt; to jump into an interactive REPL (Read Eval Print Loop) where you can run client commands directly from the shell.&lt;/p&gt;
&lt;p&gt;First, however, you&amp;rsquo;ll need to launch &lt;code&gt;redis-server&lt;/code&gt; so that you have a running Redis server to talk to.  A common way to do this in development is to start a server at &lt;a href=&quot;https://en.wikipedia.org/wiki/Localhost&quot;&gt;localhost&lt;/a&gt; (IPv4 address &lt;code&gt;127.0.0.1&lt;/code&gt;), which is the default unless you tell Redis otherwise.  You can also pass &lt;code&gt;redis-server&lt;/code&gt; the name of your configuration file, which is akin to specifying all of its key-value pairs as command-line arguments:&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; redis-server /etc/redis/6379.conf
&lt;span class=&quot;go&quot;&gt;31829:C 07 Mar 2019 08:45:04.030 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;31829:C 07 Mar 2019 08:45:04.030 # Redis version=5.0.3, bits=64, commit=00000000, modified=0, pid=31829, just started&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;31829:C 07 Mar 2019 08:45:04.030 # Configuration loaded&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;We set the &lt;code&gt;daemonize&lt;/code&gt; configuration option to &lt;code&gt;yes&lt;/code&gt;, so the server runs in the background.  (Otherwise, use &lt;code&gt;--daemonize yes&lt;/code&gt; as an option to &lt;code&gt;redis-server&lt;/code&gt;.)&lt;/p&gt;
&lt;p&gt;Now you&amp;rsquo;re ready to launch the Redis REPL.  Enter &lt;code&gt;redis-cli&lt;/code&gt; on your command line.  You&amp;rsquo;ll see the server&amp;rsquo;s &lt;em&gt;host:port&lt;/em&gt; pair followed by a &lt;code&gt;&amp;gt;&lt;/code&gt; prompt:&lt;/p&gt;
&lt;div class=&quot;highlight redis&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;127.0.0.1:6379&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Here&amp;rsquo;s one of the simplest Redis commands, &lt;a href=&quot;https://redis.io/commands/ping&quot;&gt;&lt;code&gt;PING&lt;/code&gt;&lt;/a&gt;, which just tests connectivity to the server and returns &lt;code&gt;&quot;PONG&quot;&lt;/code&gt; if things are okay:&lt;/p&gt;
&lt;div class=&quot;highlight redis&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;127.0.0.1:6379&amp;gt;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;PING&lt;/span&gt;
PONG
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Redis commands are case-insensitive, although their Python counterparts are most definitely not.&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; As another sanity check, you can search for the process ID of the Redis server with &lt;code&gt;pgrep&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; pgrep redis-server
&lt;span class=&quot;go&quot;&gt;26983&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;To kill the server, use &lt;code&gt;pkill redis-server&lt;/code&gt; from the command line.  On Mac OS X, you can also use &lt;code&gt;redis-cli shutdown&lt;/code&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;Next, we&amp;rsquo;ll use some of the common Redis commands and compare them to what they would look like in pure Python.&lt;/p&gt;
&lt;h3 id=&quot;redis-as-a-python-dictionary&quot;&gt;Redis as a Python Dictionary&lt;/h3&gt;
&lt;p&gt;Redis stands for &lt;strong&gt;Remote Dictionary Service&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&amp;ldquo;You mean, like a Python &lt;a href=&quot;https://realpython.com/python-dicts/&quot;&gt;dictionary&lt;/a&gt;?&amp;rdquo; you may ask.&lt;/p&gt;
&lt;p&gt;Yes.  Broadly speaking, there are many parallels you can draw between a Python dictionary (or generic hash table) and what Redis is and does:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;A Redis database holds &lt;em&gt;key:value&lt;/em&gt; pairs and supports commands such as &lt;code&gt;GET&lt;/code&gt;, &lt;code&gt;SET&lt;/code&gt;, and &lt;code&gt;DEL&lt;/code&gt;, as well as &lt;a href=&quot;https://redis.io/commands&quot;&gt;several hundred&lt;/a&gt; additional commands.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Redis &lt;strong&gt;keys&lt;/strong&gt; are always strings.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Redis &lt;strong&gt;values&lt;/strong&gt; may be a number of different data types.  We&amp;rsquo;ll cover some of the more essential value data types in this tutorial: &lt;code&gt;string&lt;/code&gt;, &lt;code&gt;list&lt;/code&gt;, &lt;code&gt;hashes&lt;/code&gt;, and &lt;code&gt;sets&lt;/code&gt;.  Some advanced types include &lt;a href=&quot;https://redis.io/commands#geo&quot;&gt;geospatial items&lt;/a&gt; and the new &lt;a href=&quot;https://redis.io/commands#stream&quot;&gt;stream&lt;/a&gt; type.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Many Redis commands operate in constant O(1) time, just like retrieving a value from a Python &lt;code&gt;dict&lt;/code&gt; or any hash table.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Redis creator Salvatore Sanfilippo would probably not love the comparison of a Redis database to a plain-vanilla  Python &lt;code&gt;dict&lt;/code&gt;.  He calls the project a &amp;ldquo;data structure server&amp;rdquo; (rather than a key-value store, such as &lt;a href=&quot;https://www.memcached.org/&quot;&gt;memcached&lt;/a&gt;) because, to its credit, Redis supports storing additional types of &lt;em&gt;key:value&lt;/em&gt; data types besides &lt;em&gt;string:string&lt;/em&gt;.  But for our purposes here, it&amp;rsquo;s a useful comparison if you&amp;rsquo;re familiar with Python&amp;rsquo;s dictionary object.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s jump in and learn by example.  Our first toy database (with ID 0) will be a mapping of &lt;em&gt;country:capital city&lt;/em&gt;, where we use &lt;a href=&quot;https://redis.io/commands/set&quot;&gt;&lt;code&gt;SET&lt;/code&gt;&lt;/a&gt; to set key-value pairs:&lt;/p&gt;
&lt;div class=&quot;highlight redis&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;127.0.0.1:6379&amp;gt;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;SET&lt;/span&gt; Bahamas Nassau
OK
&lt;span class=&quot;gp&quot;&gt;127.0.0.1:6379&amp;gt;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;SET&lt;/span&gt; Croatia Zagreb
OK
&lt;span class=&quot;gp&quot;&gt;127.0.0.1:6379&amp;gt;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;GET&lt;/span&gt; Croatia
&amp;quot;Zagreb&amp;quot;
&lt;span class=&quot;gp&quot;&gt;127.0.0.1:6379&amp;gt;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;GET&lt;/span&gt; Japan
&lt;span class=&quot;kt&quot;&gt;(nil)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The corresponding sequence of statements in pure Python would look like this:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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;capitals&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;capitals&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;Bahamas&amp;quot;&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;s2&quot;&gt;&amp;quot;Nassau&amp;quot;&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;capitals&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;Croatia&amp;quot;&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;s2&quot;&gt;&amp;quot;Zagreb&amp;quot;&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;capitals&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;Croatia&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;&amp;#39;Zagreb&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;capitals&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;Japan&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# None&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;We use &lt;code&gt;capitals.get(&quot;Japan&quot;)&lt;/code&gt; rather than &lt;code&gt;capitals[&quot;Japan&quot;]&lt;/code&gt; because Redis will return &lt;code&gt;nil&lt;/code&gt; rather than an error when a key is not found, which is analogous to Python&amp;rsquo;s &lt;code&gt;None&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Redis also allows you to set and get multiple key-value pairs in one command, &lt;a href=&quot;https://redis.io/commands/mset&quot;&gt;&lt;code&gt;MSET&lt;/code&gt;&lt;/a&gt; and &lt;a href=&quot;https://redis.io/commands/mget&quot;&gt;&lt;code&gt;MGET&lt;/code&gt;&lt;/a&gt;, respectively:&lt;/p&gt;
&lt;div class=&quot;highlight redis&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;127.0.0.1:6379&amp;gt;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;MSET&lt;/span&gt; Lebanon Beirut Norway Oslo France Paris
OK
&lt;span class=&quot;gp&quot;&gt;127.0.0.1:6379&amp;gt;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;MGET&lt;/span&gt; Lebanon Norway Bahamas
1) &amp;quot;Beirut&amp;quot;
2) &amp;quot;Oslo&amp;quot;
3) &amp;quot;Nassau&amp;quot;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The closest thing in Python is with &lt;code&gt;dict.update()&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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;capitals&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;gp&quot;&gt;... &lt;/span&gt;    &lt;span class=&quot;s2&quot;&gt;&amp;quot;Lebanon&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;Beirut&amp;quot;&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;s2&quot;&gt;&amp;quot;Norway&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;Oslo&amp;quot;&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;s2&quot;&gt;&amp;quot;France&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;Paris&amp;quot;&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;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;capitals&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;k&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;k&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;Lebanon&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;Norway&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;Bahamas&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)]&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;[&amp;#39;Beirut&amp;#39;, &amp;#39;Oslo&amp;#39;, &amp;#39;Nassau&amp;#39;]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;We use &lt;code&gt;.get()&lt;/code&gt; rather than &lt;code&gt;.__getitem__()&lt;/code&gt; to mimic Redis&amp;rsquo; behavior of returning a null-like value when no key is found.&lt;/p&gt;
&lt;p&gt;As a third example, the &lt;a href=&quot;https://redis.io/commands/exists&quot;&gt;&lt;code&gt;EXISTS&lt;/code&gt;&lt;/a&gt; command does what it sounds like, which is to check if a key exists:&lt;/p&gt;
&lt;div class=&quot;highlight redis&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;127.0.0.1:6379&amp;gt;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;EXISTS&lt;/span&gt; Norway
&lt;span class=&quot;kt&quot;&gt;(integer)&lt;/span&gt; 1
&lt;span class=&quot;gp&quot;&gt;127.0.0.1:6379&amp;gt;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;EXISTS&lt;/span&gt; Sweden
&lt;span class=&quot;kt&quot;&gt;(integer)&lt;/span&gt; 0
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Python has the &lt;code&gt;in&lt;/code&gt; keyword to test the same thing, which routes to &lt;code&gt;dict.__contains__(key)&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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;s2&quot;&gt;&amp;quot;Norway&amp;quot;&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;capitals&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;True&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;Sweden&amp;quot;&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;capitals&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;False&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;These few examples are meant to show, using native Python, what&amp;rsquo;s happening at a high level with a few common Redis commands.  There&amp;rsquo;s no client-server component here to the Python examples, and &lt;code&gt;redis-py&lt;/code&gt; has not yet entered the picture. This is only meant to show Redis functionality by example.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s a summary of the few Redis commands you&amp;rsquo;ve seen and their functional Python equivalents:&lt;/p&gt;
&lt;div class=&quot;card mb-3&quot; id=&quot;collapse_cardffcb17&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;#collapseffcb17&quot; aria-expanded=&quot;false&quot; aria-controls=&quot;collapseffcb17&quot;&gt;SET Bahamas Nassau&lt;/button&gt; &lt;button class=&quot;btn btn-link float-right&quot; data-toggle=&quot;collapse&quot; data-target=&quot;#collapseffcb17&quot; aria-expanded=&quot;false&quot; aria-controls=&quot;collapseffcb17&quot;&gt;Show/Hide&lt;/button&gt;&lt;/p&gt;&lt;/div&gt;
&lt;div id=&quot;collapseffcb17&quot; class=&quot;collapse&quot; data-parent=&quot;#collapse_cardffcb17&quot;&gt;&lt;div class=&quot;card-body&quot; markdown=&quot;1&quot;&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;capitals&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;Bahamas&amp;quot;&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;s2&quot;&gt;&amp;quot;Nassau&amp;quot;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;/div&gt;&lt;/div&gt;

&lt;/div&gt;
&lt;div class=&quot;card mb-3&quot; id=&quot;collapse_carda7d597&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;#collapsea7d597&quot; aria-expanded=&quot;false&quot; aria-controls=&quot;collapsea7d597&quot;&gt;GET Croatia&lt;/button&gt; &lt;button class=&quot;btn btn-link float-right&quot; data-toggle=&quot;collapse&quot; data-target=&quot;#collapsea7d597&quot; aria-expanded=&quot;false&quot; aria-controls=&quot;collapsea7d597&quot;&gt;Show/Hide&lt;/button&gt;&lt;/p&gt;&lt;/div&gt;
&lt;div id=&quot;collapsea7d597&quot; class=&quot;collapse&quot; data-parent=&quot;#collapse_carda7d597&quot;&gt;&lt;div class=&quot;card-body&quot; markdown=&quot;1&quot;&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;capitals&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;Croatia&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;/div&gt;&lt;/div&gt;

&lt;/div&gt;
&lt;div class=&quot;card mb-3&quot; id=&quot;collapse_cardab860c&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;#collapseab860c&quot; aria-expanded=&quot;false&quot; aria-controls=&quot;collapseab860c&quot;&gt;MSET Lebanon Beirut Norway Oslo France Paris&lt;/button&gt; &lt;button class=&quot;btn btn-link float-right&quot; data-toggle=&quot;collapse&quot; data-target=&quot;#collapseab860c&quot; aria-expanded=&quot;false&quot; aria-controls=&quot;collapseab860c&quot;&gt;Show/Hide&lt;/button&gt;&lt;/p&gt;&lt;/div&gt;
&lt;div id=&quot;collapseab860c&quot; class=&quot;collapse&quot; data-parent=&quot;#collapse_cardab860c&quot;&gt;&lt;div class=&quot;card-body&quot; markdown=&quot;1&quot;&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;capitals&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;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;s2&quot;&gt;&amp;quot;Lebanon&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;Beirut&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s2&quot;&gt;&amp;quot;Norway&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;Oslo&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s2&quot;&gt;&amp;quot;France&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;Paris&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;/pre&gt;&lt;/div&gt;

&lt;/div&gt;&lt;/div&gt;

&lt;/div&gt;
&lt;div class=&quot;card mb-3&quot; id=&quot;collapse_cardbcb4d2&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;#collapsebcb4d2&quot; aria-expanded=&quot;false&quot; aria-controls=&quot;collapsebcb4d2&quot;&gt;MGET Lebanon Norway Bahamas&lt;/button&gt; &lt;button class=&quot;btn btn-link float-right&quot; data-toggle=&quot;collapse&quot; data-target=&quot;#collapsebcb4d2&quot; aria-expanded=&quot;false&quot; aria-controls=&quot;collapsebcb4d2&quot;&gt;Show/Hide&lt;/button&gt;&lt;/p&gt;&lt;/div&gt;
&lt;div id=&quot;collapsebcb4d2&quot; class=&quot;collapse&quot; data-parent=&quot;#collapse_cardbcb4d2&quot;&gt;&lt;div class=&quot;card-body&quot; markdown=&quot;1&quot;&gt;

&lt;div class=&quot;highlight python&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;capitals&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;k&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;k&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;Lebanon&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;Norway&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;Bahamas&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;/div&gt;&lt;/div&gt;

&lt;/div&gt;
&lt;div class=&quot;card mb-3&quot; id=&quot;collapse_carda6599a&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;#collapsea6599a&quot; aria-expanded=&quot;false&quot; aria-controls=&quot;collapsea6599a&quot;&gt;EXISTS Norway&lt;/button&gt; &lt;button class=&quot;btn btn-link float-right&quot; data-toggle=&quot;collapse&quot; data-target=&quot;#collapsea6599a&quot; aria-expanded=&quot;false&quot; aria-controls=&quot;collapsea6599a&quot;&gt;Show/Hide&lt;/button&gt;&lt;/p&gt;&lt;/div&gt;
&lt;div id=&quot;collapsea6599a&quot; class=&quot;collapse&quot; data-parent=&quot;#collapse_carda6599a&quot;&gt;&lt;div class=&quot;card-body&quot; markdown=&quot;1&quot;&gt;

&lt;div class=&quot;highlight python&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;Norway&amp;quot;&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;capitals&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;/div&gt;&lt;/div&gt;

&lt;/div&gt;
&lt;p&gt;The Python Redis client library, &lt;code&gt;redis-py&lt;/code&gt;, that you&amp;rsquo;ll dive into shortly in this article, does things differently.  It encapsulates an actual TCP connection to a Redis server and sends raw commands, as bytes serialized using the &lt;a href=&quot;https://redis.io/topics/protocol&quot;&gt;REdis Serialization Protocol&lt;/a&gt; (RESP), to the server.  It then takes the raw reply and parses it back into a Python object such as &lt;code&gt;bytes&lt;/code&gt;, &lt;code&gt;int&lt;/code&gt;, or even &lt;code&gt;datetime.datetime&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;: So far, you&amp;rsquo;ve been talking to the Redis server through the interactive &lt;code&gt;redis-cli&lt;/code&gt; REPL.  You can also &lt;a href=&quot;https://redis.io/topics/rediscli&quot;&gt;issue commands directly&lt;/a&gt;, in the same way that you would pass the name of a script to the &lt;code&gt;python&lt;/code&gt; executable, such as &lt;code&gt;python myscript.py&lt;/code&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;So far, you&amp;rsquo;ve seen a few of Redis&amp;rsquo; fundamental data types, which is a mapping of &lt;em&gt;string:string&lt;/em&gt;.  While this key-value pair is common in most key-value stores, Redis offers a number of other possible value types, which you&amp;rsquo;ll see next.&lt;/p&gt;
&lt;h3 id=&quot;more-data-types-in-python-vs-redis&quot;&gt;More Data Types in Python vs Redis&lt;/h3&gt;
&lt;p&gt;Before you fire up the &lt;code&gt;redis-py&lt;/code&gt; Python client, it also helps to have a basic grasp on a few more Redis data types.  To be clear, all Redis keys are strings.  It&amp;rsquo;s the value that can take on data types (or structures) in addition to the string values used in the examples so far.&lt;/p&gt;
&lt;p&gt;A &lt;strong&gt;hash&lt;/strong&gt; is a mapping of &lt;em&gt;string:string&lt;/em&gt;, called &lt;strong&gt;field-value&lt;/strong&gt; pairs, that sits under one top-level key:&lt;/p&gt;
&lt;div class=&quot;highlight redis&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;127.0.0.1:6379&amp;gt;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;HSET&lt;/span&gt; realpython url &amp;quot;https://realpython.com/&amp;quot;
&lt;span class=&quot;kt&quot;&gt;(integer)&lt;/span&gt; 1
&lt;span class=&quot;gp&quot;&gt;127.0.0.1:6379&amp;gt;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;HSET&lt;/span&gt; realpython github realpython
&lt;span class=&quot;kt&quot;&gt;(integer)&lt;/span&gt; 1
&lt;span class=&quot;gp&quot;&gt;127.0.0.1:6379&amp;gt;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;HSET&lt;/span&gt; realpython fullname &amp;quot;Real Python&amp;quot;
&lt;span class=&quot;kt&quot;&gt;(integer)&lt;/span&gt; 1
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This sets three field-value pairs for one &lt;strong&gt;key&lt;/strong&gt;, &lt;code&gt;&quot;realpython&quot;&lt;/code&gt;.  If you&amp;rsquo;re used to Python&amp;rsquo;s terminology and objects, this can be confusing.  A Redis hash is roughly analogous to a Python &lt;code&gt;dict&lt;/code&gt; that is nested one level deep:&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;data&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;realpython&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;url&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;https://realpython.com/&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s2&quot;&gt;&amp;quot;github&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;realpython&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s2&quot;&gt;&amp;quot;fullname&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;Real Python&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;/pre&gt;&lt;/div&gt;

&lt;p&gt;Redis&amp;rsquo; fields are akin to the Python keys of each nested key-value pair in the inner dictionary above.  Redis reserves the term &lt;strong&gt;key&lt;/strong&gt; for the top-level database key that holds the hash structure itself.&lt;/p&gt;
&lt;p&gt;Just like there&amp;rsquo;s &lt;code&gt;MSET&lt;/code&gt; for basic &lt;em&gt;string:string&lt;/em&gt; key-value pairs, there is also &lt;a href=&quot;https://redis.io/commands/hmset&quot;&gt;&lt;code&gt;HMSET&lt;/code&gt;&lt;/a&gt; for hashes to set multiple pairs &lt;em&gt;within&lt;/em&gt; the hash value object:&lt;/p&gt;
&lt;div class=&quot;highlight redis&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;127.0.0.1:6379&amp;gt;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;HMSET&lt;/span&gt; pypa url &amp;quot;https://www.pypa.io/&amp;quot; github pypa fullname &amp;quot;Python Packaging Authority&amp;quot;
OK
&lt;span class=&quot;gp&quot;&gt;127.0.0.1:6379&amp;gt;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;HGETALL&lt;/span&gt; pypa
1) &amp;quot;url&amp;quot;
2) &amp;quot;https://www.pypa.io/&amp;quot;
3) &amp;quot;github&amp;quot;
4) &amp;quot;pypa&amp;quot;
5) &amp;quot;fullname&amp;quot;
6) &amp;quot;Python Packaging Authority&amp;quot;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Using &lt;code&gt;HMSET&lt;/code&gt; is probably a closer parallel for the way that we assigned &lt;code&gt;data&lt;/code&gt; to a nested dictionary above, rather than setting each nested pair as is done with &lt;code&gt;HSET&lt;/code&gt;. &lt;/p&gt;
&lt;p&gt;Two additional value types are &lt;a href=&quot;https://redis.io/topics/data-types-intro#redis-lists&quot;&gt;&lt;strong&gt;lists&lt;/strong&gt;&lt;/a&gt; and &lt;a href=&quot;https://redis.io/topics/data-types-intro#redis-sets&quot;&gt;&lt;strong&gt;sets&lt;/strong&gt;&lt;/a&gt;, which can take the place of a hash or string as a Redis value.  They are largely what they sound like, so I won&amp;rsquo;t take up your time with additional examples.  Hashes, lists, and sets each have some commands that are particular to that given data type, which are in some cases denoted by their initial letter:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Hashes:&lt;/strong&gt; Commands to operate on hashes begin with an &lt;code&gt;H&lt;/code&gt;, such as &lt;code&gt;HSET&lt;/code&gt;, &lt;code&gt;HGET&lt;/code&gt;, or &lt;code&gt;HMSET&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Sets:&lt;/strong&gt; Commands to operate on sets begin with an &lt;code&gt;S&lt;/code&gt;, such as &lt;code&gt;SCARD&lt;/code&gt;, which gets the number of elements at the set value corresponding to a given key.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Lists:&lt;/strong&gt; Commands to operate on lists begin with an &lt;code&gt;L&lt;/code&gt; or &lt;code&gt;R&lt;/code&gt;.  Examples include &lt;code&gt;LPOP&lt;/code&gt; and &lt;code&gt;RPUSH&lt;/code&gt;.  The &lt;code&gt;L&lt;/code&gt; or &lt;code&gt;R&lt;/code&gt; refers to which side of the list is operated on.  A few list commands are also prefaced with a &lt;code&gt;B&lt;/code&gt;, which means &lt;strong&gt;blocking&lt;/strong&gt;.  A blocking operation doesn&amp;rsquo;t let other operations interrupt it while it&amp;rsquo;s executing.  For instance, &lt;code&gt;BLPOP&lt;/code&gt; executes a blocking left-pop on a list structure.&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; One noteworthy feature of Redis&amp;rsquo; list type is that it is a linked list rather than an array.  This means that appending is O(1) while indexing at an arbitrary index number is O(N).&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;Here is a quick listing of commands that are particular to the string, hash, list, and set data types in Redis:&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;Type&lt;/th&gt;
&lt;th&gt;Commands&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Sets&lt;/td&gt;
&lt;td&gt;&lt;code&gt;SADD&lt;/code&gt;, &lt;code&gt;SCARD&lt;/code&gt;, &lt;code&gt;SDIFF&lt;/code&gt;, &lt;code&gt;SDIFFSTORE&lt;/code&gt;, &lt;code&gt;SINTER&lt;/code&gt;, &lt;code&gt;SINTERSTORE&lt;/code&gt;, &lt;code&gt;SISMEMBER&lt;/code&gt;, &lt;code&gt;SMEMBERS&lt;/code&gt;, &lt;code&gt;SMOVE&lt;/code&gt;, &lt;code&gt;SPOP&lt;/code&gt;, &lt;code&gt;SRANDMEMBER&lt;/code&gt;, &lt;code&gt;SREM&lt;/code&gt;, &lt;code&gt;SSCAN&lt;/code&gt;, &lt;code&gt;SUNION&lt;/code&gt;, &lt;code&gt;SUNIONSTORE&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hashes&lt;/td&gt;
&lt;td&gt;&lt;code&gt;HDEL&lt;/code&gt;, &lt;code&gt;HEXISTS&lt;/code&gt;, &lt;code&gt;HGET&lt;/code&gt;, &lt;code&gt;HGETALL&lt;/code&gt;, &lt;code&gt;HINCRBY&lt;/code&gt;, &lt;code&gt;HINCRBYFLOAT&lt;/code&gt;, &lt;code&gt;HKEYS&lt;/code&gt;, &lt;code&gt;HLEN&lt;/code&gt;, &lt;code&gt;HMGET&lt;/code&gt;, &lt;code&gt;HMSET&lt;/code&gt;, &lt;code&gt;HSCAN&lt;/code&gt;, &lt;code&gt;HSET&lt;/code&gt;, &lt;code&gt;HSETNX&lt;/code&gt;, &lt;code&gt;HSTRLEN&lt;/code&gt;, &lt;code&gt;HVALS&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Lists&lt;/td&gt;
&lt;td&gt;&lt;code&gt;BLPOP&lt;/code&gt;, &lt;code&gt;BRPOP&lt;/code&gt;, &lt;code&gt;BRPOPLPUSH&lt;/code&gt;, &lt;code&gt;LINDEX&lt;/code&gt;, &lt;code&gt;LINSERT&lt;/code&gt;, &lt;code&gt;LLEN&lt;/code&gt;, &lt;code&gt;LPOP&lt;/code&gt;, &lt;code&gt;LPUSH&lt;/code&gt;, &lt;code&gt;LPUSHX&lt;/code&gt;, &lt;code&gt;LRANGE&lt;/code&gt;, &lt;code&gt;LREM&lt;/code&gt;, &lt;code&gt;LSET&lt;/code&gt;, &lt;code&gt;LTRIM&lt;/code&gt;, &lt;code&gt;RPOP&lt;/code&gt;, &lt;code&gt;RPOPLPUSH&lt;/code&gt;, &lt;code&gt;RPUSH&lt;/code&gt;, &lt;code&gt;RPUSHX&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Strings&lt;/td&gt;
&lt;td&gt;&lt;code&gt;APPEND&lt;/code&gt;, &lt;code&gt;BITCOUNT&lt;/code&gt;, &lt;code&gt;BITFIELD&lt;/code&gt;, &lt;code&gt;BITOP&lt;/code&gt;, &lt;code&gt;BITPOS&lt;/code&gt;, &lt;code&gt;DECR&lt;/code&gt;, &lt;code&gt;DECRBY&lt;/code&gt;, &lt;code&gt;GET&lt;/code&gt;, &lt;code&gt;GETBIT&lt;/code&gt;, &lt;code&gt;GETRANGE&lt;/code&gt;, &lt;code&gt;GETSET&lt;/code&gt;, &lt;code&gt;INCR&lt;/code&gt;, &lt;code&gt;INCRBY&lt;/code&gt;, &lt;code&gt;INCRBYFLOAT&lt;/code&gt;, &lt;code&gt;MGET&lt;/code&gt;, &lt;code&gt;MSET&lt;/code&gt;, &lt;code&gt;MSETNX&lt;/code&gt;, &lt;code&gt;PSETEX&lt;/code&gt;, &lt;code&gt;SET&lt;/code&gt;, &lt;code&gt;SETBIT&lt;/code&gt;, &lt;code&gt;SETEX&lt;/code&gt;, &lt;code&gt;SETNX&lt;/code&gt;, &lt;code&gt;SETRANGE&lt;/code&gt;, &lt;code&gt;STRLEN&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;p&gt;This table isn&amp;rsquo;t a complete picture of Redis commands and types.  There&amp;rsquo;s a smorgasbord of more advanced data types, such as &lt;a href=&quot;https://redis.io/commands#geo&quot;&gt;geospatial items&lt;/a&gt;, &lt;a href=&quot;https://redis.io/commands#sorted_set&quot;&gt;sorted sets&lt;/a&gt;, and &lt;a href=&quot;https://redis.io/commands#hyperloglog&quot;&gt;HyperLogLog&lt;/a&gt;.  At the Redis &lt;a href=&quot;https://redis.io/commands&quot;&gt;commands&lt;/a&gt; page, you can filter by data-structure group.  There is also the &lt;a href=&quot;https://redis.io/topics/data-types&quot;&gt;data types summary&lt;/a&gt; and &lt;a href=&quot;https://redis.io/topics/data-types-intro&quot;&gt;introduction to Redis data types&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Since we&amp;rsquo;re going to be switching over to doing things in Python, you can now clear your toy database with &lt;a href=&quot;https://redis.io/commands/flushdb&quot;&gt;&lt;code&gt;FLUSHDB&lt;/code&gt;&lt;/a&gt; and quit the &lt;code&gt;redis-cli&lt;/code&gt; REPL:&lt;/p&gt;
&lt;div class=&quot;highlight redis&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;127.0.0.1:6379&amp;gt;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;FLUSHDB&lt;/span&gt;
OK
&lt;span class=&quot;gp&quot;&gt;127.0.0.1:6379&amp;gt;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;QUIT&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This will bring you back to your shell prompt.  You can leave &lt;code&gt;redis-server&lt;/code&gt; running in the background, since you&amp;rsquo;ll need it for the rest of the tutorial also.&lt;/p&gt;
&lt;h2 id=&quot;using-redis-py-redis-in-python&quot;&gt;Using &lt;code&gt;redis-py&lt;/code&gt;: Redis in Python&lt;/h2&gt;
&lt;p&gt;Now that you&amp;rsquo;ve mastered some basics of Redis, it&amp;rsquo;s time to jump into &lt;code&gt;redis-py&lt;/code&gt;, the Python client that lets you talk to Redis from a user-friendly Python API.&lt;/p&gt;
&lt;h3 id=&quot;first-steps&quot;&gt;First Steps&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/andymccurdy/redis-py&quot;&gt;&lt;code&gt;redis-py&lt;/code&gt;&lt;/a&gt; is a well-established Python client library that lets you talk to a Redis server directly through Python calls:&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 redis
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Next, make sure that your Redis server is still up and running in the background.  You can check with &lt;code&gt;pgrep redis-server&lt;/code&gt;, and if you come up empty-handed, then restart a local server with &lt;code&gt;redis-server /etc/redis/6379.conf&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Now, let&amp;rsquo;s get into the Python-centric part of things.  Here&amp;rsquo;s the &amp;ldquo;hello world&amp;rdquo; of &lt;code&gt;redis-py&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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;lineno&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;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;redis&lt;/span&gt;
&lt;span class=&quot;lineno&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;r&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;redis&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Redis&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;gp&quot;&gt;&amp;gt;&amp;gt;&amp;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;n&quot;&gt;mset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;Croatia&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;Zagreb&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;Bahamas&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;Nassau&amp;quot;&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;go&quot;&gt;True&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 5 &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&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;Bahamas&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;go&quot;&gt;b&amp;#39;Nassau&amp;#39;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;code&gt;Redis&lt;/code&gt;, used in Line 2, is the central class of the package and the workhorse by which you execute (almost) any Redis command.  The TCP socket connection and reuse is done for you behind the scenes, and you call Redis commands using methods on the class instance &lt;code&gt;r&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Notice also that the type of the returned object, &lt;code&gt;b&#39;Nassau&#39;&lt;/code&gt; in Line 6, is Python&amp;rsquo;s &lt;a href=&quot;https://docs.python.org/3/library/stdtypes.html#bytes&quot;&gt;&lt;code&gt;bytes&lt;/code&gt;&lt;/a&gt; type, not &lt;code&gt;str&lt;/code&gt;.  It is &lt;code&gt;bytes&lt;/code&gt; rather than &lt;code&gt;str&lt;/code&gt; that is the most common return type across &lt;code&gt;redis-py&lt;/code&gt;, so you may need to call &lt;code&gt;r.get(&quot;Bahamas&quot;).decode(&quot;utf-8&quot;)&lt;/code&gt; depending on what you want to actually do with the returned bytestring.&lt;/p&gt;
&lt;p&gt;Does the code above look familiar?  The methods in almost all cases match the name of the Redis command that does the same thing.  Here, you called &lt;code&gt;r.mset()&lt;/code&gt; and &lt;code&gt;r.get()&lt;/code&gt;, which correspond to &lt;code&gt;MSET&lt;/code&gt; and &lt;code&gt;GET&lt;/code&gt; in the native Redis API.&lt;/p&gt;
&lt;p&gt;This also means that &lt;code&gt;HGETALL&lt;/code&gt; becomes &lt;code&gt;r.hgetall()&lt;/code&gt;, &lt;code&gt;PING&lt;/code&gt; becomes &lt;code&gt;r.ping()&lt;/code&gt;, and so on.  There are a &lt;a href=&quot;https://github.com/andymccurdy/redis-py#api-reference&quot;&gt;few&lt;/a&gt; exceptions, but the rule holds for the large majority of commands.&lt;/p&gt;
&lt;p&gt;While the Redis command arguments usually translate into a similar-looking method signature, they take Python objects.  For example, the call to &lt;code&gt;r.mset()&lt;/code&gt; in the example above uses a Python &lt;code&gt;dict&lt;/code&gt; as its first argument, rather than a sequence of bytestrings.&lt;/p&gt;
&lt;p&gt;We built the &lt;code&gt;Redis&lt;/code&gt; instance &lt;code&gt;r&lt;/code&gt; with no arguments, but it comes bundled with a number of &lt;a href=&quot;https://github.com/andymccurdy/redis-py/blob/b940d073de4c13f8dfb08728965c6ac7c183c935/redis/client.py#L605&quot;&gt;parameters&lt;/a&gt; if you need them:&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;# From redis/client.py&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Redis&lt;/span&gt;&lt;span class=&quot;p&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;__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;n&quot;&gt;host&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;localhost&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;port&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;6379&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;mi&quot;&gt;0&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;kc&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;socket_timeout&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;c1&quot;&gt;# ...&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You can see that the default &lt;em&gt;hostname:port&lt;/em&gt; pair is &lt;code&gt;localhost:6379&lt;/code&gt;, which is exactly what we need in the case of our locally kept &lt;code&gt;redis-server&lt;/code&gt; instance.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;db&lt;/code&gt; parameter is the database number.  You can manage multiple databases in Redis at once, and each is identified by an integer.  The max number of databases is 16 by default.&lt;/p&gt;
&lt;p&gt;When you run just &lt;code&gt;redis-cli&lt;/code&gt; from the command line, this starts you at database 0.  Use the &lt;code&gt;-n&lt;/code&gt; flag to start a new database, as in &lt;code&gt;redis-cli -n 5&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;allowed-key-types&quot;&gt;Allowed Key Types&lt;/h3&gt;
&lt;p&gt;One thing that&amp;rsquo;s worth knowing is that &lt;code&gt;redis-py&lt;/code&gt; requires that you pass it keys that are &lt;code&gt;bytes&lt;/code&gt;, &lt;code&gt;str&lt;/code&gt;, &lt;code&gt;int&lt;/code&gt;, or &lt;code&gt;float&lt;/code&gt;.  (It will convert the last 3 of these types to &lt;code&gt;bytes&lt;/code&gt; before sending them off to the server.)&lt;/p&gt;
&lt;p&gt;Consider a case where you want to use calendar dates as keys:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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;datetime&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;today&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;date&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;today&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;visitors&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;dan&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;jon&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;alex&amp;quot;&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;r&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sadd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;today&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;visitors&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;gt&quot;&gt;Traceback (most recent call last):&lt;/span&gt;
&lt;span class=&quot;err&quot;&gt;# ...&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;redis.exceptions.DataError: Invalid input of type: &amp;#39;date&amp;#39;.&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Convert to a byte, string or number first.&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You&amp;rsquo;ll need to explicitly convert the Python &lt;code&gt;date&lt;/code&gt; object to &lt;code&gt;str&lt;/code&gt;, which you can do with &lt;code&gt;.isoformat()&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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;stoday&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;today&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;c1&quot;&gt;# Python 3.7+, or use str(today)&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;stoday&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;&amp;#39;2019-03-10&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;r&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sadd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;stoday&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;visitors&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# sadd: set-add&lt;/span&gt;
&lt;span class=&quot;go&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;r&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;smembers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;stoday&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;{b&amp;#39;dan&amp;#39;, b&amp;#39;alex&amp;#39;, b&amp;#39;jon&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;r&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scard&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;today&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;3&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;To recap, Redis itself only allows strings as keys.  &lt;code&gt;redis-py&lt;/code&gt; is a bit more liberal in what Python types it will accept, although it ultimately converts everything to bytes before sending them off to a Redis server.&lt;/p&gt;
&lt;h3 id=&quot;example-pyhatscom&quot;&gt;Example: PyHats.com&lt;/h3&gt;
&lt;p&gt;It&amp;rsquo;s time to break out a fuller example.  Let&amp;rsquo;s pretend we&amp;rsquo;ve decided to start a lucrative website, PyHats.com, that sells outrageously overpriced hats to anyone who will buy them, and hired you to build the site.&lt;/p&gt;
&lt;p&gt;You&amp;rsquo;ll use Redis to handle some of the product catalog, inventorying, and bot traffic detection for PyHats.com.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s day one for the site, and we&amp;rsquo;re going to be selling three limited-edition hats.  Each hat gets held in a Redis hash of field-value pairs, and the hash has a key that is a prefixed random integer , such as &lt;code&gt;hat:56854717&lt;/code&gt;.  Using the &lt;code&gt;hat:&lt;/code&gt; prefix is Redis convention for creating a sort of namespace within a Redis database:&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;random&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;seed&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;444&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;hats&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;f&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;hat:{random.getrandbits(32)}&amp;quot;&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;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;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;color&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;black&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s2&quot;&gt;&amp;quot;price&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;49.99&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s2&quot;&gt;&amp;quot;style&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;fitted&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s2&quot;&gt;&amp;quot;quantity&amp;quot;&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;s2&quot;&gt;&amp;quot;npurchased&amp;quot;&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;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;color&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;maroon&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s2&quot;&gt;&amp;quot;price&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;59.99&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s2&quot;&gt;&amp;quot;style&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;hipster&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s2&quot;&gt;&amp;quot;quantity&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;500&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s2&quot;&gt;&amp;quot;npurchased&amp;quot;&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;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;color&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;green&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s2&quot;&gt;&amp;quot;price&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;99.99&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s2&quot;&gt;&amp;quot;style&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;baseball&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s2&quot;&gt;&amp;quot;quantity&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;200&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s2&quot;&gt;&amp;quot;npurchased&amp;quot;&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;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;Let&amp;rsquo;s start with database &lt;code&gt;1&lt;/code&gt; since we used database &lt;code&gt;0&lt;/code&gt; in a previous example:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;redis&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Redis&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;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;To do an initial write of this data into Redis, we can use &lt;code&gt;.hmset()&lt;/code&gt; (hash multi-set), calling it for each dictionary.  The &amp;ldquo;multi&amp;rdquo; is a reference to setting multiple field-value pairs, where &amp;ldquo;field&amp;rdquo; in this case corresponds to a key of any of the nested dictionaries in &lt;code&gt;hats&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;o&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;with&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;n&quot;&gt;pipeline&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;pipe&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;o&quot;&gt;...&lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;h_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;hat&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;hats&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;items&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;o&quot;&gt;...&lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;pipe&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hmset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;h_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;hat&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;o&quot;&gt;...&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;pipe&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;execute&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;Pipeline&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ConnectionPool&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Connection&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;host&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;localhost&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;port&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;6379&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;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&amp;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;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ConnectionPool&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Connection&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;host&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;localhost&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;port&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;6379&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;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&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;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ConnectionPool&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Connection&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;host&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;localhost&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;port&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;6379&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;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&amp;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;kc&quot;&gt;True&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;kc&quot;&gt;True&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;o&quot;&gt;&amp;gt;&amp;gt;&amp;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;n&quot;&gt;bgsave&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;kc&quot;&gt;True&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The code block above also introduces the concept of Redis &lt;a href=&quot;https://redis.io/topics/pipelining&quot;&gt;&lt;strong&gt;pipelining&lt;/strong&gt;&lt;/a&gt;, which is a way to cut down the number of round-trip transactions that you need to write or read data from your Redis server.  If you would have just called &lt;code&gt;r.hmset()&lt;/code&gt; three times, then this would necessitate a back-and-forth round trip operation for each row written.&lt;/p&gt;
&lt;p&gt;With a pipeline, all the commands are buffered on the client side and then sent at once, in one fell swoop, using &lt;code&gt;pipe.hmset()&lt;/code&gt; in Line 3.  This is why the three &lt;code&gt;True&lt;/code&gt; responses are all returned at once, when you call &lt;code&gt;pipe.execute()&lt;/code&gt; in Line 4.  You&amp;rsquo;ll see a more advanced use case for a pipeline shortly.&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 Redis docs provide an &lt;a href=&quot;https://redis.io/topics/mass-insert&quot;&gt;example&lt;/a&gt; of doing this same thing with the &lt;code&gt;redis-cli&lt;/code&gt;, where you can pipe the contents of a local file to do mass insertion.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;Let&amp;rsquo;s do a quick check that everything is there in our Redis database:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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;pprint&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;n&quot;&gt;hgetall&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;hat:56854717&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;{b&amp;#39;color&amp;#39;: b&amp;#39;green&amp;#39;,&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt; b&amp;#39;npurchased&amp;#39;: b&amp;#39;0&amp;#39;,&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt; b&amp;#39;price&amp;#39;: b&amp;#39;99.99&amp;#39;,&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt; b&amp;#39;quantity&amp;#39;: b&amp;#39;200&amp;#39;,&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt; b&amp;#39;style&amp;#39;: b&amp;#39;baseball&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;r&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;keys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# Careful on a big DB. keys() is O(N)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;[b&amp;#39;56854717&amp;#39;, b&amp;#39;1236154736&amp;#39;, b&amp;#39;1326692461&amp;#39;]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The first thing that we want to simulate is what happens when a user clicks &lt;em&gt;Purchase&lt;/em&gt;.  If the item is in stock, increase its &lt;code&gt;npurchased&lt;/code&gt; by 1 and decrease its &lt;code&gt;quantity&lt;/code&gt; (inventory) by 1.  You can use &lt;code&gt;.hincrby()&lt;/code&gt; to do this:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hincrby&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;hat:56854717&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;quantity&amp;quot;&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;go&quot;&gt;199&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&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hget&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;hat:56854717&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;quantity&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;b&amp;#39;199&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;r&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hincrby&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;hat:56854717&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;npurchased&amp;quot;&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&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;: &lt;code&gt;HINCRBY&lt;/code&gt; still operates on a hash value that is a string, but it tries to interpret the string as a base-10 64-bit signed integer to execute the operation.&lt;/p&gt;
&lt;p&gt;This applies to other commands related to incrementing and decrementing for other data structures, namely &lt;code&gt;INCR&lt;/code&gt;, &lt;code&gt;INCRBY&lt;/code&gt;, &lt;code&gt;INCRBYFLOAT&lt;/code&gt;, &lt;code&gt;ZINCRBY&lt;/code&gt;, and &lt;code&gt;HINCRBYFLOAT&lt;/code&gt;.  You&amp;rsquo;ll get an error if the string at the value can&amp;rsquo;t be represented as an integer.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;It isn&amp;rsquo;t really that simple, though.  Changing the &lt;code&gt;quantity&lt;/code&gt; and &lt;code&gt;npurchased&lt;/code&gt; in two lines of code hides the reality that a click, purchase, and payment entails more than this.  We need to do a few more checks to make sure we don&amp;rsquo;t leave someone with a lighter wallet and no hat:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Step 1:&lt;/strong&gt; Check if the item is in stock, or otherwise raise an exception on the backend.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Step 2:&lt;/strong&gt; If it is in stock, then execute the transaction, decrease the &lt;code&gt;quantity&lt;/code&gt; field, and increase the &lt;code&gt;npurchased&lt;/code&gt; field.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Step 3:&lt;/strong&gt; Be alert for any changes that alter the inventory in between the first two steps (a &lt;a href=&quot;https://realpython.com/python-concurrency/#threading-version&quot;&gt;race condition&lt;/a&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Step 1 is relatively straightforward: it consists of an &lt;code&gt;.hget()&lt;/code&gt; to check the available quantity.&lt;/p&gt;
&lt;p&gt;Step 2 is a little bit more involved.  The pair of increase and decrease operations need to be executed &lt;strong&gt;atomically&lt;/strong&gt;: either both should be completed successfully, or neither should be (in the case that at least one fails).  &lt;/p&gt;
&lt;p&gt;With client-server frameworks, it&amp;rsquo;s always crucial to pay attention to atomicity and look out for what could go wrong in instances where multiple clients are trying to talk to the server at once.  The answer to this in Redis is to use a &lt;a href=&quot;https://redis.io/topics/transactions&quot;&gt;&lt;strong&gt;transaction&lt;/strong&gt;&lt;/a&gt; block, meaning that either both or neither of the commands get through.&lt;/p&gt;
&lt;p&gt;In &lt;code&gt;redis-py&lt;/code&gt;, &lt;code&gt;Pipeline&lt;/code&gt; is a &lt;strong&gt;transactional pipeline&lt;/strong&gt; class by default.  This means that, even though the class is actually named for something else (pipelining), it can be used to create a transaction block also.&lt;/p&gt;
&lt;p&gt;In Redis, a transaction starts with &lt;code&gt;MULTI&lt;/code&gt; and ends with &lt;code&gt;EXEC&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight redis&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;gp&quot;&gt;127.0.0.1:6379&amp;gt;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;MULTI&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 2 &lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;127.0.0.1:6379&amp;gt;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;HINCRBY&lt;/span&gt; 56854717 quantity -1
&lt;span class=&quot;lineno&quot;&gt; 3 &lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;127.0.0.1:6379&amp;gt;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;HINCRBY&lt;/span&gt; 56854717 npurchased 1
&lt;span class=&quot;lineno&quot;&gt; 4 &lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;127.0.0.1:6379&amp;gt;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;EXEC&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;code&gt;MULTI&lt;/code&gt; (Line 1) marks the start of the transaction, and &lt;code&gt;EXEC&lt;/code&gt; (Line 4) marks the end.  Everything in between is executed as one all-or-nothing buffered sequence of commands.  This means that it will be impossible to decrement &lt;code&gt;quantity&lt;/code&gt; (Line 2) but then have the balancing &lt;code&gt;npurchased&lt;/code&gt; increment operation fail (Line 3).&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s circle back to Step 3: we need to be aware of any changes that alter the inventory in between the first two steps.&lt;/p&gt;
&lt;p&gt;Step 3 is the trickiest.  Let&amp;rsquo;s say that there is one lone hat remaining in our inventory.  In between the time that User A checks the quantity of hats remaining and actually processes their transaction, User B also checks the inventory and finds likewise that there is one hat listed in stock.  Both users will be allowed to purchase the hat, but we have 1 hat to sell, not 2, so we&amp;rsquo;re on the hook and one user is out of their money.  Not good.&lt;/p&gt;
&lt;p&gt;Redis has a clever answer for the dilemma in Step 3: it&amp;rsquo;s called &lt;a href=&quot;https://en.wikipedia.org/wiki/Optimistic_concurrency_control&quot;&gt;&lt;strong&gt;optimistic locking&lt;/strong&gt;&lt;/a&gt;, and is different than how typical locking works in an RDBMS such as PostgreSQL.  Optimistic locking, in a nutshell, means that the calling function (client) does not acquire a lock, but rather monitors for changes in the data it is writing to &lt;em&gt;during the time it would have held a lock&lt;/em&gt;.  If there&amp;rsquo;s a conflict during that time, the calling function simply tries the whole process again.&lt;/p&gt;
&lt;p&gt;You can effect optimistic locking by using the &lt;code&gt;WATCH&lt;/code&gt; command (&lt;code&gt;.watch()&lt;/code&gt; in &lt;code&gt;redis-py&lt;/code&gt;), which provides a &lt;a href=&quot;https://redis.io/topics/transactions#cas&quot;&gt;&lt;strong&gt;check-and-set&lt;/strong&gt;&lt;/a&gt; behavior.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s introduce a big chunk of code and walk through it afterwards step by step.  You can picture &lt;code&gt;buyitem()&lt;/code&gt; as being called any time a user clicks on a &lt;em&gt;Buy Now&lt;/em&gt; or &lt;em&gt;Purchase&lt;/em&gt; button.  Its purpose is to confirm the item is in stock and take an action based on that result, all in a safe manner that looks out for race conditions and retries if one is detected:&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;redis&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;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;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;OutOfStockError&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ne&quot;&gt;Exception&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;sd&quot;&gt;&amp;quot;&amp;quot;&amp;quot;Raised when PyHats.com is all out of today&amp;#39;s hottest hat&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 8 &lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 9 &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;buyitem&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;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;redis&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Redis&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;itemid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;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;10 &lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;with&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;n&quot;&gt;pipeline&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;pipe&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;error_count&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;lineno&quot;&gt;12 &lt;/span&gt;        &lt;span class=&quot;k&quot;&gt;while&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;13 &lt;/span&gt;            &lt;span class=&quot;k&quot;&gt;try&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;c1&quot;&gt;# Get available inventory, watching for changes&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;15 &lt;/span&gt;                &lt;span class=&quot;c1&quot;&gt;# related to this itemid before the transaction&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;16 &lt;/span&gt;                &lt;span class=&quot;n&quot;&gt;pipe&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;watch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;itemid&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;nleft&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;bytes&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;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hget&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;itemid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;quantity&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;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;nleft&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;sa&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;0&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;n&quot;&gt;pipe&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;multi&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;pipe&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hincrby&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;itemid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;quantity&amp;quot;&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;lineno&quot;&gt;21 &lt;/span&gt;                    &lt;span class=&quot;n&quot;&gt;pipe&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hincrby&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;itemid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;npurchased&amp;quot;&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;22 &lt;/span&gt;                    &lt;span class=&quot;n&quot;&gt;pipe&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;execute&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;break&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;24 &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;25 &lt;/span&gt;                    &lt;span class=&quot;c1&quot;&gt;# Stop watching the itemid and raise to break out&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;26 &lt;/span&gt;                    &lt;span class=&quot;n&quot;&gt;pipe&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;unwatch&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;k&quot;&gt;raise&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;OutOfStockError&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;f&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;Sorry, &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{itemid}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; is out of stock!&amp;quot;&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;k&quot;&gt;except&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;redis&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;WatchError&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;c1&quot;&gt;# Log total num. of errors by this user to buy this item,&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;32 &lt;/span&gt;                &lt;span class=&quot;c1&quot;&gt;# then try the same process again of WATCH/HGET/MULTI/EXEC&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;33 &lt;/span&gt;                &lt;span class=&quot;n&quot;&gt;error_count&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;lineno&quot;&gt;34 &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;warning&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;s2&quot;&gt;&amp;quot;WatchError #&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%d&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%s&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;; retrying&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;n&quot;&gt;error_count&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;itemid&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;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;None&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The critical line occurs at Line 16 with &lt;code&gt;pipe.watch(itemid)&lt;/code&gt;, which tells Redis to monitor the given &lt;code&gt;itemid&lt;/code&gt; for any changes to its value.  The program checks the inventory through the call to &lt;code&gt;r.hget(itemid, &quot;quantity&quot;)&lt;/code&gt;, in Line 17:&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;n&quot;&gt;pipe&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;watch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;itemid&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;nleft&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;bytes&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;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hget&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;itemid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;quantity&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;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;nleft&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;sa&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;0&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;c1&quot;&gt;# Item in stock. Proceed with transaction.&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;If the inventory gets touched during this short window between when the user checks the item stock and tries to purchase it, then Redis will return an error, and &lt;code&gt;redis-py&lt;/code&gt; will raise a &lt;code&gt;WatchError&lt;/code&gt; (Line 30).  That is, if any of the hash pointed to by &lt;code&gt;itemid&lt;/code&gt; changes after the &lt;code&gt;.hget()&lt;/code&gt; call but before the subsequent &lt;code&gt;.hincrby()&lt;/code&gt; calls in Lines 20 and 21, then we&amp;rsquo;ll re-run the whole process in another iteration of the &lt;code&gt;while True&lt;/code&gt; loop as a result.&lt;/p&gt;
&lt;p&gt;This is the &amp;ldquo;optimistic&amp;rdquo; part of the locking: rather than letting the client have a time-consuming total lock on the database through the getting and setting operations, we leave it up to Redis to notify the client and user only in the case that calls for a retry of the inventory check.&lt;/p&gt;
&lt;p&gt;One key here is in understanding the difference between &lt;strong&gt;client-side&lt;/strong&gt; and &lt;strong&gt;server-side&lt;/strong&gt; operations:&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;nleft&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;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hget&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;itemid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;quantity&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This Python assignment brings the result of &lt;code&gt;r.hget()&lt;/code&gt; client-side.  Conversely, methods that you call on &lt;code&gt;pipe&lt;/code&gt; effectively buffer all of the commands into one, and then send them to the server in a single request:&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;n&quot;&gt;pipe&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;multi&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;pipe&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hincrby&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;itemid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;quantity&amp;quot;&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;lineno&quot;&gt;18 &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pipe&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hincrby&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;itemid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;npurchased&amp;quot;&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;19 &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pipe&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;execute&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;No data comes back to the client side in the middle of the transactional pipeline.  You need to call &lt;code&gt;.execute()&lt;/code&gt; (Line 19) to get the sequence of results back all at once.&lt;/p&gt;
&lt;p&gt;Even though this block contains two commands, it consists of exactly one round-trip operation from client to server and back.&lt;/p&gt;
&lt;p&gt;This means that the client can&amp;rsquo;t immediately &lt;em&gt;use&lt;/em&gt; the result of &lt;code&gt;pipe.hincrby(itemid, &quot;quantity&quot;, -1)&lt;/code&gt;, from Line 20, because methods on a &lt;code&gt;Pipeline&lt;/code&gt; return just the &lt;code&gt;pipe&lt;/code&gt; instance itself.  We haven&amp;rsquo;t asked anything from the server at this point.  While normally &lt;code&gt;.hincrby()&lt;/code&gt; returns the resulting value, you can&amp;rsquo;t immediately reference it on the client side until the entire transaction is completed.&lt;/p&gt;
&lt;p&gt;There&amp;rsquo;s a catch-22: this is also why you can&amp;rsquo;t put the call to &lt;code&gt;.hget()&lt;/code&gt; into the transaction block.  If you did this, then you&amp;rsquo;d be unable to know if you want to increment the &lt;code&gt;npurchased&lt;/code&gt; field yet, since you can&amp;rsquo;t get real-time results from commands that are inserted into a transactional pipeline.&lt;/p&gt;
&lt;p&gt;Finally, if the inventory sits at zero, then we &lt;code&gt;UNWATCH&lt;/code&gt; the item ID and raise an &lt;code&gt;OutOfStockError&lt;/code&gt; (Line 27), ultimately displaying that coveted &lt;em&gt;Sold Out&lt;/em&gt; page that will make our hat buyers desperately want to buy even more of our hats at ever more outlandish prices:&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;24 &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;25 &lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;# Stop watching the itemid and raise to break out&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;26 &lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;pipe&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;unwatch&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;k&quot;&gt;raise&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;OutOfStockError&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;f&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;Sorry, &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{itemid}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; is out of stock!&amp;quot;&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;/pre&gt;&lt;/div&gt;

&lt;p&gt;Here&amp;rsquo;s an illustration.  Keep in mind that our starting quantity is &lt;code&gt;199&lt;/code&gt; for hat 56854717 since we called &lt;code&gt;.hincrby()&lt;/code&gt; above.  Let&amp;rsquo;s mimic 3 purchases, which should modify the &lt;code&gt;quantity&lt;/code&gt; and &lt;code&gt;npurchased&lt;/code&gt; fields:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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;buyitem&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;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;hat:56854717&amp;quot;&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;buyitem&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;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;hat:56854717&amp;quot;&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;buyitem&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;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;hat:56854717&amp;quot;&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;r&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hmget&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;hat:56854717&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;quantity&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;npurchased&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# Hash multi-get&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;[b&amp;#39;196&amp;#39;, b&amp;#39;4&amp;#39;]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now, we can fast-forward through more purchases, mimicking a stream of purchases until the stock depletes to zero.  Again, picture these coming from a whole bunch of different clients rather than just one &lt;code&gt;Redis&lt;/code&gt; instance:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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;c1&quot;&gt;# Buy remaining 196 hats for item 56854717 and deplete stock to 0&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;_&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;196&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;buyitem&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;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;hat:56854717&amp;quot;&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;r&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hmget&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;hat:56854717&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;quantity&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;npurchased&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;[b&amp;#39;0&amp;#39;, b&amp;#39;200&amp;#39;]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now, when some poor user is late to the game, they should be met with an &lt;code&gt;OutOfStockError&lt;/code&gt; that tells our application to render an error message page on the frontend:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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;buyitem&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;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;hat:56854717&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;gt&quot;&gt;Traceback (most recent call last):&lt;/span&gt;
  File &lt;span class=&quot;nb&quot;&gt;&amp;quot;&amp;lt;stdin&amp;gt;&amp;quot;&lt;/span&gt;, line &lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;, in &lt;span class=&quot;n&quot;&gt;&amp;lt;module&amp;gt;&lt;/span&gt;
  File &lt;span class=&quot;nb&quot;&gt;&amp;quot;&amp;lt;stdin&amp;gt;&amp;quot;&lt;/span&gt;, line &lt;span class=&quot;m&quot;&gt;20&lt;/span&gt;, in &lt;span class=&quot;n&quot;&gt;buyitem&lt;/span&gt;
&lt;span class=&quot;gr&quot;&gt;__main__.OutOfStockError&lt;/span&gt;: &lt;span class=&quot;n&quot;&gt;Sorry, hat:56854717 is out of stock!&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Looks like it&amp;rsquo;s time to restock.&lt;/p&gt;
&lt;h3 id=&quot;using-key-expiry&quot;&gt;Using Key Expiry&lt;/h3&gt;
&lt;p&gt;Let&amp;rsquo;s introduce &lt;strong&gt;key expiry&lt;/strong&gt;, which is another distinguishing feature in Redis.  When you &lt;a href=&quot;https://redis.io/commands/expire&quot;&gt;&lt;strong&gt;expire&lt;/strong&gt;&lt;/a&gt; a key, that key and its corresponding value will be automatically deleted from the database after a certain number of seconds or at a certain timestamp.&lt;/p&gt;
&lt;p&gt;In &lt;code&gt;redis-py&lt;/code&gt;, one way that you can accomplish this is through &lt;code&gt;.setex()&lt;/code&gt;, which lets you set a basic &lt;em&gt;string:string&lt;/em&gt; key-value pair with an expiration:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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;lineno&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;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;timedelta&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;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;# setex: &amp;quot;SET&amp;quot; with expiration&lt;/span&gt;
&lt;span class=&quot;lineno&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;r&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;setex&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;gp&quot;&gt;... &lt;/span&gt;    &lt;span class=&quot;s2&quot;&gt;&amp;quot;runner&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;gp&quot;&gt;... &lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;timedelta&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;minutes&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;lineno&quot;&gt; 7 &lt;/span&gt;&lt;span class=&quot;gp&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;s2&quot;&gt;&amp;quot;now you see me, now you don&amp;#39;t&amp;quot;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 8 &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;lineno&quot;&gt; 9 &lt;/span&gt;&lt;span class=&quot;go&quot;&gt;True&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You can specify the second argument as a number in seconds or a &lt;code&gt;timedelta&lt;/code&gt; object, as in Line 6 above.  I like the latter because it seems less ambiguous and more deliberate.&lt;/p&gt;
&lt;p&gt;There are also methods (and corresponding Redis commands, of course) to get the remaining lifetime (&lt;strong&gt;time-to-live&lt;/strong&gt;) of a key that you&amp;rsquo;ve set to expire:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ttl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;runner&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# &amp;quot;Time To Live&amp;quot;, in seconds&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;58&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&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pttl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;runner&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# Like ttl, but milliseconds&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;54368&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Below, you can accelerate the window until expiration, and then watch the key expire, after which &lt;code&gt;r.get()&lt;/code&gt; will return &lt;code&gt;None&lt;/code&gt; and &lt;code&gt;.exists()&lt;/code&gt; will return &lt;code&gt;0&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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&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;runner&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# Not expired yet&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;b&amp;quot;now you see me, now you don&amp;#39;t&amp;quot;&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&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;expire&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;runner&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;timedelta&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;seconds&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;c1&quot;&gt;# Set new expire window&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;True&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;# Pause for a few seconds&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&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;runner&amp;quot;&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;r&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;runner&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# Key &amp;amp; value are both gone (expired)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;0&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The table below summarizes commands related to key-value expiration, including the ones covered above.  The explanations are taken directly from &lt;code&gt;redis-py&lt;/code&gt; method docstrings:&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;Signature&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;r.setex(name, time, value)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Sets the value of key &lt;code&gt;name&lt;/code&gt; to &lt;code&gt;value&lt;/code&gt; that expires in &lt;code&gt;time&lt;/code&gt; seconds, where &lt;code&gt;time&lt;/code&gt; can be represented by an &lt;code&gt;int&lt;/code&gt; or a Python &lt;code&gt;timedelta&lt;/code&gt; object&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;r.psetex(name, time_ms, value)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Sets the value of key &lt;code&gt;name&lt;/code&gt; to &lt;code&gt;value&lt;/code&gt; that expires in &lt;code&gt;time_ms&lt;/code&gt; milliseconds, where &lt;code&gt;time_ms&lt;/code&gt; can be represented by an &lt;code&gt;int&lt;/code&gt; or a Python &lt;code&gt;timedelta&lt;/code&gt; object&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;r.expire(name, time)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Sets an expire flag on key &lt;code&gt;name&lt;/code&gt; for &lt;code&gt;time&lt;/code&gt; seconds, where &lt;code&gt;time&lt;/code&gt; can be represented by an &lt;code&gt;int&lt;/code&gt; or a Python &lt;code&gt;timedelta&lt;/code&gt; object&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;r.expireat(name, when)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Sets an expire flag on key &lt;code&gt;name&lt;/code&gt;, where &lt;code&gt;when&lt;/code&gt; can be represented as an &lt;code&gt;int&lt;/code&gt; indicating Unix time or a Python &lt;code&gt;datetime&lt;/code&gt; object&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;r.persist(name)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Removes an expiration on &lt;code&gt;name&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;r.pexpire(name, time)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Sets an expire flag on key &lt;code&gt;name&lt;/code&gt; for &lt;code&gt;time&lt;/code&gt; milliseconds, and &lt;code&gt;time&lt;/code&gt; can be represented by an &lt;code&gt;int&lt;/code&gt; or a Python &lt;code&gt;timedelta&lt;/code&gt; object&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;r.pexpireat(name, when)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Sets an expire flag on key &lt;code&gt;name&lt;/code&gt;, where &lt;code&gt;when&lt;/code&gt; can be represented as an &lt;code&gt;int&lt;/code&gt; representing Unix time in milliseconds (Unix time * 1000) or a Python &lt;code&gt;datetime&lt;/code&gt; object&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;r.pttl(name)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Returns the number of milliseconds until the key &lt;code&gt;name&lt;/code&gt; will expire&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;r.ttl(name)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Returns the number of seconds until the key &lt;code&gt;name&lt;/code&gt; will expire&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;h3 id=&quot;pyhatscom-part-2&quot;&gt;PyHats.com, Part 2&lt;/h3&gt;
&lt;p&gt;A few days after its debut, PyHats.com has attracted so much hype that some enterprising users are creating bots to buy hundreds of items within seconds, which you&amp;rsquo;ve decided isn&amp;rsquo;t good for the long-term health of your hat business.&lt;/p&gt;
&lt;p&gt;Now that you&amp;rsquo;ve seen how to expire keys, let&amp;rsquo;s put it to use on the backend of PyHats.com.&lt;/p&gt;
&lt;p&gt;We&amp;rsquo;re going to create a new Redis client that acts as a consumer (or watcher) and processes a stream of incoming IP addresses, which in turn may come from multiple HTTPS connections to the website&amp;rsquo;s server.&lt;/p&gt;
&lt;p&gt;The watcher&amp;rsquo;s goal is to monitor a stream of IP addresses from multiple sources, keeping an eye out for a flood of requests from a single address within a suspiciously short amount of time.&lt;/p&gt;
&lt;p&gt;Some middleware on the website server pushes all incoming IP addresses into a Redis list with &lt;code&gt;.lpush()&lt;/code&gt;.  Here&amp;rsquo;s a crude way of mimicking some incoming IPs, using a fresh Redis database:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;redis&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Redis&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;mi&quot;&gt;5&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;r&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lpush&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;ips&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;51.218.112.236&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&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;r&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lpush&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;ips&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;90.213.45.98&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&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;r&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lpush&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;ips&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;115.215.230.176&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&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;r&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lpush&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;ips&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;51.218.112.236&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;4&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;As you can see, &lt;code&gt;.lpush()&lt;/code&gt; returns the length of the list after the push operation succeeds.  Each call of &lt;code&gt;.lpush()&lt;/code&gt; puts the IP at the beginning of the Redis list that is keyed by the string &lt;code&gt;&quot;ips&quot;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;In this simplified simulation, the requests are all technically from the same client, but you can think of them as potentially coming from many different clients and all being pushed to the same database on the same Redis server.&lt;/p&gt;
&lt;p&gt;Now, open up a new shell tab or window and launch a new Python REPL.  In this shell, you&amp;rsquo;ll create a new client that serves a very different purpose than the rest, which sits in an endless &lt;code&gt;while True&lt;/code&gt; loop and does a blocking left-pop &lt;a href=&quot;https://redis.io/commands/blpop&quot;&gt;&lt;code&gt;BLPOP&lt;/code&gt;&lt;/a&gt; call on the &lt;code&gt;ips&lt;/code&gt; list, processing each address:&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;c1&quot;&gt;# New shell window or tab&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;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;datetime&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 4 &lt;/span&gt;&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;ipaddress&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;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;redis&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;c1&quot;&gt;# Where we put all the bad egg IP addresses&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 9 &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;blacklist&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;lineno&quot;&gt;10 &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;MAXVISITS&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;15&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;11 &lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;12 &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ipwatcher&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;redis&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Redis&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;mi&quot;&gt;5&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;lineno&quot;&gt;14 &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;while&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;15 &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;addr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ipwatcher&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;blpop&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;ips&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;addr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ipaddress&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ip_address&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;addr&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;s2&quot;&gt;&amp;quot;utf-8&amp;quot;&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;now&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;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;lineno&quot;&gt;18 &lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;addrts&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;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{addr}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{now.minute}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;19 &lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ipwatcher&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;incrby&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;addrts&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;20 &lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MAXVISITS&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;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;s2&quot;&gt;&amp;quot;Hat bot detected!:  &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{addr}&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;22 &lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;blacklist&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;addr&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;else&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;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;s2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{now}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;:  saw &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{addr}&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;25 &lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ipwatcher&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;expire&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;addrts&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;/pre&gt;&lt;/div&gt;

&lt;p&gt;Let&amp;rsquo;s walk through a few important concepts.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;ipwatcher&lt;/code&gt; acts like a &lt;a href=&quot;https://realpython.com/intro-to-python-threading/#producer-consumer-threading&quot;&gt;consumer&lt;/a&gt;, sitting around and waiting for new IPs to be pushed on the &lt;code&gt;&quot;ips&quot;&lt;/code&gt; Redis list.  It receives them as &lt;code&gt;bytes&lt;/code&gt;, such as b&amp;rdquo;51.218.112.236&amp;rdquo;, and makes them into a more proper &lt;a href=&quot;https://docs.python.org/3/library/ipaddress.html#address-objects&quot;&gt;address object&lt;/a&gt; with the &lt;code&gt;ipaddress&lt;/code&gt; module:&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;15 &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;addr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ipwatcher&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;blpop&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;ips&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;addr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ipaddress&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ip_address&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;addr&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;s2&quot;&gt;&amp;quot;utf-8&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Then you form a Redis string key using the address and minute of the hour at which the &lt;code&gt;ipwatcher&lt;/code&gt; saw the address, incrementing the corresponding count by &lt;code&gt;1&lt;/code&gt; and getting the new count in the process:&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;17 &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;now&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;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;lineno&quot;&gt;18 &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;addrts&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;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{addr}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{now.minute}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;19 &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;n&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ipwatcher&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;incrby&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;addrts&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;/pre&gt;&lt;/div&gt;

&lt;p&gt;If the address has been seen more than &lt;code&gt;MAXVISITS&lt;/code&gt;, then it looks as if we have a PyHats.com web scraper on our hands trying to create the next &lt;a href=&quot;https://en.wikipedia.org/wiki/Tulip_mania&quot;&gt;tulip bubble&lt;/a&gt;.  Alas, we have no choice but to give this user back something like a dreaded 403 status code.&lt;/p&gt;
&lt;p&gt;We use &lt;code&gt;ipwatcher.expire(addrts, 60)&lt;/code&gt; to expire the &lt;em&gt;(address minute)&lt;/em&gt; combination 60 seconds from when it was last seen.  This is to prevent our database from becoming clogged up with stale one-time page viewers.&lt;/p&gt;
&lt;p&gt;If you execute this code block in a new shell, you should immediately see this output:&lt;/p&gt;
&lt;div class=&quot;highlight text&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;2019-03-11 15:10:41.489214:  saw 51.218.112.236
2019-03-11 15:10:41.490298:  saw 115.215.230.176
2019-03-11 15:10:41.490839:  saw 90.213.45.98
2019-03-11 15:10:41.491387:  saw 51.218.112.236
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The output appears right away because those four IPs were sitting in the queue-like list keyed by &lt;code&gt;&quot;ips&quot;&lt;/code&gt;, waiting to be pulled out by our &lt;code&gt;ipwatcher&lt;/code&gt;.  Using &lt;code&gt;.blpop()&lt;/code&gt; (or the &lt;code&gt;BLPOP&lt;/code&gt; command) will block until an item is available in the list, then pops it off.  It behaves like Python&amp;rsquo;s &lt;a href=&quot;https://docs.python.org/3/library/queue.html#queue.Queue.get&quot;&gt;&lt;code&gt;Queue.get()&lt;/code&gt;&lt;/a&gt;, which also blocks until an item is available.&lt;/p&gt;
&lt;p&gt;Besides just spitting out IP addresses, our &lt;code&gt;ipwatcher&lt;/code&gt; has a second job.  For a given minute of an hour (minute 1 through minute 60), &lt;code&gt;ipwatcher&lt;/code&gt; will classify an IP address as a hat-bot if it sends 15 or more &lt;code&gt;GET&lt;/code&gt; requests in that minute.&lt;/p&gt;
&lt;p&gt;Switch back to your first shell and mimic a page scraper that blasts the site with 20 requests in a few milliseconds:&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;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;20&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;n&quot;&gt;lpush&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;ips&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;104.174.118.18&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Finally, toggle back to the second shell holding &lt;code&gt;ipwatcher&lt;/code&gt;, and you should see an output like this:&lt;/p&gt;
&lt;div class=&quot;highlight text&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;2019-03-11 15:15:43.041363:  saw 104.174.118.18
2019-03-11 15:15:43.042027:  saw 104.174.118.18
2019-03-11 15:15:43.042598:  saw 104.174.118.18
2019-03-11 15:15:43.043143:  saw 104.174.118.18
2019-03-11 15:15:43.043725:  saw 104.174.118.18
2019-03-11 15:15:43.044244:  saw 104.174.118.18
2019-03-11 15:15:43.044760:  saw 104.174.118.18
2019-03-11 15:15:43.045288:  saw 104.174.118.18
2019-03-11 15:15:43.045806:  saw 104.174.118.18
2019-03-11 15:15:43.046318:  saw 104.174.118.18
2019-03-11 15:15:43.046829:  saw 104.174.118.18
2019-03-11 15:15:43.047392:  saw 104.174.118.18
2019-03-11 15:15:43.047966:  saw 104.174.118.18
2019-03-11 15:15:43.048479:  saw 104.174.118.18
Hat bot detected!:  104.174.118.18
Hat bot detected!:  104.174.118.18
Hat bot detected!:  104.174.118.18
Hat bot detected!:  104.174.118.18
Hat bot detected!:  104.174.118.18
Hat bot detected!:  104.174.118.18
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now, &lt;span class=&quot;keys&quot;&gt;&lt;kbd class=&quot;key-control&quot;&gt;Ctrl&lt;/kbd&gt;&lt;span&gt;+&lt;/span&gt;&lt;kbd class=&quot;key-c&quot;&gt;C&lt;/kbd&gt;&lt;/span&gt; out of the &lt;code&gt;while True&lt;/code&gt; loop and you&amp;rsquo;ll see that the offending IP has been added to your blacklist:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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;blacklist&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;{IPv4Address(&amp;#39;104.174.118.18&amp;#39;)}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Can you find the defect in this detection system?  The filter checks the minute as &lt;code&gt;.minute&lt;/code&gt; rather than the &lt;em&gt;last 60 seconds&lt;/em&gt; (a rolling minute).  Implementing a rolling check to monitor how many times a user has been seen in the last 60 seconds would be trickier.  There&amp;rsquo;s a crafty solution using using Redis&amp;rsquo; sorted sets at &lt;a href=&quot;https://engineering.classdojo.com/blog/2015/02/06/rolling-rate-limiter/&quot;&gt;ClassDojo&lt;/a&gt;.  Josiah Carlson&amp;rsquo;s &lt;a href=&quot;https://realpython.com/asins/1617290858/&quot;&gt;&lt;em&gt;Redis in Action&lt;/em&gt;&lt;/a&gt; also presents a more elaborate and general-purpose example of this section using an IP-to-location cache table.&lt;/p&gt;
&lt;h3 id=&quot;persistence-and-snapshotting&quot;&gt;Persistence and Snapshotting&lt;/h3&gt;
&lt;p&gt;One of the reasons that Redis is so fast in both read and write operations is that the database is held in memory (RAM) on the server.  However, a Redis database can also be stored (persisted) to disk in a process called &lt;a href=&quot;https://redis.io/topics/persistence#snapshotting&quot;&gt;snapshotting&lt;/a&gt;.  The point behind this is to keep a physical backup in binary format so that data can be reconstructed and put back into memory when needed, such as at server startup.&lt;/p&gt;
&lt;p&gt;You already enabled snapshotting without knowing it when you set up basic configuration at the beginning of this tutorial with the &lt;code&gt;save&lt;/code&gt; option:&lt;/p&gt;
&lt;div class=&quot;highlight text&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;# /etc/redis/6379.conf

port              6379
daemonize         yes
&lt;span class=&quot;hll&quot;&gt;save              60 1
&lt;/span&gt;bind              127.0.0.1
tcp-keepalive     300
dbfilename        dump.rdb
dir               ./
rdbcompression    yes
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The format is &lt;code&gt;save &amp;lt;seconds&amp;gt; &amp;lt;changes&amp;gt;&lt;/code&gt;.  This tells Redis to save the database to disk if both the given number of seconds and number of write operations against the database occurred.  In this case, we&amp;rsquo;re telling Redis to save the database to disk every 60 seconds if at least one modifying write operation occurred in that 60-second timespan.  This is a fairly aggressive setting versus the &lt;a href=&quot;http://download.redis.io/redis-stable/redis.conf&quot;&gt;sample Redis config file&lt;/a&gt;, which uses these three &lt;code&gt;save&lt;/code&gt; directives:&lt;/p&gt;
&lt;div class=&quot;highlight text&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;# Default redis/redis.conf
save 900 1
save 300 10
save 60 10000
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;An &lt;strong&gt;RDB snapshot&lt;/strong&gt; is a full (rather than incremental) point-in-time capture of the database.  (RDB refers to a Redis Database File.)  We also specified the directory and file name of the resulting data file that gets written:&lt;/p&gt;
&lt;div class=&quot;highlight text&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;# /etc/redis/6379.conf

port              6379
daemonize         yes
save              60 1
bind              127.0.0.1
tcp-keepalive     300
&lt;span class=&quot;hll&quot;&gt;dbfilename        dump.rdb
&lt;/span&gt;&lt;span class=&quot;hll&quot;&gt;dir               ./
&lt;/span&gt;&lt;span class=&quot;hll&quot;&gt;rdbcompression    yes
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This instructs Redis to save to a binary data file called &lt;code&gt;dump.rdb&lt;/code&gt; in the current working directory of wherever &lt;code&gt;redis-server&lt;/code&gt; was executed from:&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; file -b dump.rdb
&lt;span class=&quot;go&quot;&gt;data&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You can also manually invoke a save with the Redis command &lt;a href=&quot;https://redis.io/commands/bgsave&quot;&gt;&lt;code&gt;BGSAVE&lt;/code&gt;&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight redis&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;127.0.0.1:6379&amp;gt;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;BGSAVE&lt;/span&gt;
Background saving started
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The &amp;ldquo;BG&amp;rdquo; in &lt;code&gt;BGSAVE&lt;/code&gt; indicates that the save occurs in the background.  This option is available in a &lt;code&gt;redis-py&lt;/code&gt; method as well:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lastsave&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# Redis command: LASTSAVE&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;datetime.datetime(2019, 3, 10, 21, 56, 50)&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&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bgsave&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;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;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;n&quot;&gt;lastsave&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;datetime.datetime(2019, 3, 10, 22, 4, 2)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This example introduces another new command and method, &lt;code&gt;.lastsave()&lt;/code&gt;.  In Redis, it returns the Unix timestamp of the last DB save, which Python gives back to you as a &lt;code&gt;datetime&lt;/code&gt; object.  Above, you can see that the &lt;code&gt;r.lastsave()&lt;/code&gt; result changes as a result of &lt;code&gt;r.bgsave()&lt;/code&gt;.  &lt;/p&gt;
&lt;p&gt;&lt;code&gt;r.lastsave()&lt;/code&gt; will also change if you enable automatic snapshotting with the &lt;code&gt;save&lt;/code&gt; configuration option.&lt;/p&gt;
&lt;p&gt;To rephrase all of this, there are two ways to enable snapshotting:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Explicitly, through the Redis command &lt;code&gt;BGSAVE&lt;/code&gt; or &lt;code&gt;redis-py&lt;/code&gt; method &lt;code&gt;.bgsave()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Implicitly, through the &lt;code&gt;save&lt;/code&gt; configuration option (which you can also set with &lt;code&gt;.config_set()&lt;/code&gt; in &lt;code&gt;redis-py&lt;/code&gt;)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;RDB snapshotting is fast because the parent process uses the &lt;a href=&quot;http://man7.org/linux/man-pages/man2/fork.2.html&quot;&gt;&lt;code&gt;fork()&lt;/code&gt;&lt;/a&gt; system call to pass off the time-intensive write to disk to a child process, so that the parent process can continue on its way.  This is what the &lt;em&gt;background&lt;/em&gt; in &lt;code&gt;BGSAVE&lt;/code&gt; refers to.&lt;/p&gt;
&lt;p&gt;There&amp;rsquo;s also &lt;a href=&quot;https://redis.io/commands/save&quot;&gt;&lt;code&gt;SAVE&lt;/code&gt;&lt;/a&gt; (&lt;code&gt;.save()&lt;/code&gt; in &lt;code&gt;redis-py&lt;/code&gt;), but this does a synchronous (blocking) save rather than using &lt;code&gt;fork()&lt;/code&gt;, so you shouldn&amp;rsquo;t use it without a specific reason.&lt;/p&gt;
&lt;p&gt;Even though &lt;code&gt;.bgsave()&lt;/code&gt; occurs in the background, it&amp;rsquo;s not without its costs.  The time for &lt;code&gt;fork()&lt;/code&gt; itself to occur can actually be substantial if the Redis database is large enough in the first place.  &lt;/p&gt;
&lt;p&gt;If this is a concern, or if you can&amp;rsquo;t afford to miss even a tiny slice of data lost due to the periodic nature of RDB snapshotting, then you should look into the &lt;a href=&quot;https://redis.io/topics/persistence#append-only-file&quot;&gt;append-only file&lt;/a&gt; (AOF) strategy that is an alternative to snapshotting.  AOF copies Redis commands to disk in real time, allowing you to do a literal command-based reconstruction by replaying these commands.&lt;/p&gt;
&lt;h3 id=&quot;serialization-workarounds&quot;&gt;Serialization Workarounds&lt;/h3&gt;
&lt;p&gt;Let&amp;rsquo;s get back to talking about Redis data structures.  With its hash data structure, Redis in effect supports nesting one level deep:&lt;/p&gt;
&lt;div class=&quot;highlight redis&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;127.0.0.1:6379&amp;gt;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;hset&lt;/span&gt; mykey field1 value1
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The Python client equivalent would 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;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;mykey&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;field1&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;value1&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Here, you can think of &lt;code&gt;&quot;field1&quot;: &quot;value1&quot;&lt;/code&gt; as being the key-value pair of a Python dict, &lt;code&gt;{&quot;field1&quot;: &quot;value1&quot;}&lt;/code&gt;, while &lt;code&gt;mykey&lt;/code&gt; is the top-level key:&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;Redis Command&lt;/th&gt;
&lt;th&gt;Pure-Python Equivalent&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;r.set(&quot;key&quot;, &quot;value&quot;)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;r = {&quot;key&quot;: &quot;value&quot;}&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;r.hset(&quot;key&quot;, &quot;field&quot;, &quot;value&quot;)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;r = {&quot;key&quot;: {&quot;field&quot;: &quot;value&quot;}}&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;p&gt;But what if you want the value of this dictionary (the Redis hash) to contain something other than a string, such as a &lt;code&gt;list&lt;/code&gt; or nested dictionary with strings as values?&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s an example using some &lt;a href=&quot;https://realpython.com/python-json/&quot;&gt;JSON&lt;/a&gt;-like data to make the distinction clearer:&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;restaurant_484272&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;name&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;Ravagh&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s2&quot;&gt;&amp;quot;type&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;Persian&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s2&quot;&gt;&amp;quot;address&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;street&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;line1&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;11 E 30th St&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;s2&quot;&gt;&amp;quot;line2&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;APT 1&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;city&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;New York&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s2&quot;&gt;&amp;quot;state&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;NY&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s2&quot;&gt;&amp;quot;zip&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;10016&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;Say that we want to set a Redis hash with the key &lt;code&gt;484272&lt;/code&gt; and field-value pairs corresponding to the key-value pairs from &lt;code&gt;restaurant_484272&lt;/code&gt;.  Redis does not support this directly, because &lt;code&gt;restaurant_484272&lt;/code&gt; is nested:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hmset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;484272&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;restaurant_484272&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;gt&quot;&gt;Traceback (most recent call last):&lt;/span&gt;
&lt;span class=&quot;err&quot;&gt;# ...&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;redis.exceptions.DataError: Invalid input of type: &amp;#39;dict&amp;#39;.&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Convert to a byte, string or number first.&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You can in fact make this work with Redis.  There are two different ways to mimic nested data in &lt;code&gt;redis-py&lt;/code&gt; and Redis:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Serialize the values into a string with something like &lt;code&gt;json.dumps()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Use a delimiter in the key strings to mimic nesting in the values&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Let&amp;rsquo;s take a look at an example of each.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Option 1: Serialize the Values Into a String&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;You can use &lt;code&gt;json.dumps()&lt;/code&gt; to serialize the &lt;code&gt;dict&lt;/code&gt; into a JSON-formatted string:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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;json&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&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;span class=&quot;mi&quot;&gt;484272&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dumps&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;restaurant_484272&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;If you call &lt;code&gt;.get()&lt;/code&gt;, the value you get back will be a &lt;code&gt;bytes&lt;/code&gt; object, so don&amp;rsquo;t forget to deserialize it to get back the original object.  &lt;code&gt;json.dumps()&lt;/code&gt; and &lt;code&gt;json.loads()&lt;/code&gt; are inverses of each other, for serializing and deserializing data, respectively:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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;pprint&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pprint&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;pprint&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;loads&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;n&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;484272&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)))&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;{&amp;#39;address&amp;#39;: {&amp;#39;city&amp;#39;: &amp;#39;New York&amp;#39;,&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;             &amp;#39;state&amp;#39;: &amp;#39;NY&amp;#39;,&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;             &amp;#39;street&amp;#39;: &amp;#39;11 E 30th St&amp;#39;,&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;             &amp;#39;zip&amp;#39;: 10016},&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt; &amp;#39;name&amp;#39;: &amp;#39;Ravagh&amp;#39;,&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt; &amp;#39;type&amp;#39;: &amp;#39;Persian&amp;#39;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This applies to any serialization protocol, with another common choice being &lt;a href=&quot;https://github.com/yaml/pyyaml&quot;&gt;&lt;code&gt;yaml&lt;/code&gt;&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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;yaml&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# python -m pip install PyYAML&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;yaml&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;restaurant_484272&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;&amp;#39;address: {city: New York, state: NY, street: 11 E 30th St, zip: 10016}\nname: Ravagh\ntype: Persian\n&amp;#39;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;No matter what serialization protocol you choose to go with, the concept is the same: you&amp;rsquo;re taking an object that is unique to Python and converting it to a bytestring that is recognized and exchangeable across multiple languages.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Option 2: Use a Delimiter in Key Strings&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;There&amp;rsquo;s a second option that involves mimicking &amp;ldquo;nestedness&amp;rdquo; by concatenating multiple levels of keys in a Python &lt;code&gt;dict&lt;/code&gt;.  This consists of flattening the nested dictionary through &lt;a href=&quot;https://realpython.com/python-thinking-recursively/&quot;&gt;recursion&lt;/a&gt;, so that each key is a concatenated string of keys, and the values are the deepest-nested values from the original dictionary.  Consider our dictionary object &lt;code&gt;restaurant_484272&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;restaurant_484272&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;name&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;Ravagh&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s2&quot;&gt;&amp;quot;type&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;Persian&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s2&quot;&gt;&amp;quot;address&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;street&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;line1&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;11 E 30th St&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;s2&quot;&gt;&amp;quot;line2&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;APT 1&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;city&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;New York&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s2&quot;&gt;&amp;quot;state&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;NY&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s2&quot;&gt;&amp;quot;zip&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;10016&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;We want to get it into this form:&lt;/p&gt;
&lt;div class=&quot;highlight python&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;s2&quot;&gt;&amp;quot;484272:name&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;                     &lt;span class=&quot;s2&quot;&gt;&amp;quot;Ravagh&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s2&quot;&gt;&amp;quot;484272:type&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;                     &lt;span class=&quot;s2&quot;&gt;&amp;quot;Persian&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s2&quot;&gt;&amp;quot;484272:address:street:line1&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;     &lt;span class=&quot;s2&quot;&gt;&amp;quot;11 E 30th St&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s2&quot;&gt;&amp;quot;484272:address:street:line2&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;     &lt;span class=&quot;s2&quot;&gt;&amp;quot;APT 1&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s2&quot;&gt;&amp;quot;484272:address:city&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;             &lt;span class=&quot;s2&quot;&gt;&amp;quot;New York&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s2&quot;&gt;&amp;quot;484272:address:state&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;            &lt;span class=&quot;s2&quot;&gt;&amp;quot;NY&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s2&quot;&gt;&amp;quot;484272:address:zip&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;              &lt;span class=&quot;s2&quot;&gt;&amp;quot;10016&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;That&amp;rsquo;s what &lt;code&gt;setflat_skeys()&lt;/code&gt; below does, with the added feature that it does inplace &lt;code&gt;.set()&lt;/code&gt; operations on the &lt;code&gt;Redis&lt;/code&gt; instance itself rather than returning a copy of the input dictionary:&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;collections.abc&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MutableMapping&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;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;setflat_skeys&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;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;redis&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Redis&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;obj&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;dict&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;prefix&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;str&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;delim&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;str&lt;/span&gt; &lt;span class=&quot;o&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;lineno&quot;&gt; 8 &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; 9 &lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;_autopfix&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;10 &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;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;11 &lt;/span&gt;    &lt;span class=&quot;sd&quot;&gt;&amp;quot;&amp;quot;&amp;quot;Flatten `obj` and set resulting field-value pairs into `r`.&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;sd&quot;&gt;    Calls `.set()` to write to Redis instance inplace and returns None.&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;sd&quot;&gt;    `prefix` is an optional str that prefixes all keys.&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;16 &lt;/span&gt;&lt;span class=&quot;sd&quot;&gt;    `delim` is the delimiter that separates the joined, flattened keys.&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;17 &lt;/span&gt;&lt;span class=&quot;sd&quot;&gt;    `_autopfix` is used in recursive calls to created de-nested keys.&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;sd&quot;&gt;    The deepest-nested keys must be str, bytes, float, or int.&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;20 &lt;/span&gt;&lt;span class=&quot;sd&quot;&gt;    Otherwise a TypeError is raised.&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;21 &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;22 &lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;allowed_vtypes&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;nb&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;bytes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;int&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;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;key&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;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;obj&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;items&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;key&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_autopfix&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;key&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;25 &lt;/span&gt;        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;isinstance&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;allowed_vtypes&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;r&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;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{prefix}{delim}{key}&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;value&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;k&quot;&gt;elif&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;isinstance&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;MutableMapping&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;setflat_skeys&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;r&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;prefix&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;delim&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_autopfix&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;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{key}{delim}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&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;k&quot;&gt;else&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;k&quot;&gt;raise&lt;/span&gt; &lt;span class=&quot;ne&quot;&gt;TypeError&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;Unsupported value type: {type(value)}&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 function iterates over the key-value pairs of &lt;code&gt;obj&lt;/code&gt;, first checking the type of the value (Line 25) to see if it looks like it should stop recursing further and set that key-value pair.  Otherwise, if the value looks like a &lt;code&gt;dict&lt;/code&gt; (Line 27), then it recurses into that mapping, adding the previously seen keys as a key prefix (Line 28).&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s see it at work:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;flushdb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# Flush database: clear old entries&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;setflat_skeys&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;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;restaurant_484272&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;484272&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;key&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&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;r&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;keys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;484272*&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)):&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# Filter to this pattern&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;f&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;{repr(key):35}{repr(r.get(key)):15}&amp;quot;&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;b&amp;#39;484272:address:city&amp;#39;             b&amp;#39;New York&amp;#39;&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;b&amp;#39;484272:address:state&amp;#39;            b&amp;#39;NY&amp;#39;&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;b&amp;#39;484272:address:street:line1&amp;#39;     b&amp;#39;11 E 30th St&amp;#39;&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;b&amp;#39;484272:address:street:line2&amp;#39;     b&amp;#39;APT 1&amp;#39;&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;b&amp;#39;484272:address:zip&amp;#39;              b&amp;#39;10016&amp;#39;&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;b&amp;#39;484272:name&amp;#39;                     b&amp;#39;Ravagh&amp;#39;&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;b&amp;#39;484272:type&amp;#39;                     b&amp;#39;Persian&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;r&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;484272:address:street:line1&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;b&amp;#39;11 E 30th St&amp;#39;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The final loop above uses &lt;code&gt;r.keys(&quot;484272*&quot;)&lt;/code&gt;, where &lt;code&gt;&quot;484272*&quot;&lt;/code&gt; is interpreted as a pattern and matches all keys in the database that begin with &lt;code&gt;&quot;484272&quot;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Notice also how &lt;code&gt;setflat_skeys()&lt;/code&gt; calls just &lt;code&gt;.set()&lt;/code&gt; rather than &lt;code&gt;.hset()&lt;/code&gt;, because we&amp;rsquo;re working with plain &lt;em&gt;string:string&lt;/em&gt; field-value pairs, and the 484272 ID key is prepended to each field string.&lt;/p&gt;
&lt;h3 id=&quot;encryption&quot;&gt;Encryption&lt;/h3&gt;
&lt;p&gt;Another trick to help you sleep well at night is to add symmetric encryption before sending anything to a Redis server.  Consider this as an add-on to the security that you should make sure is in place by setting proper values in your &lt;a href=&quot;#configuring-redis&quot;&gt;Redis configuration&lt;/a&gt;.  The example below uses the &lt;a href=&quot;https://github.com/pyca/cryptography/&quot;&gt;&lt;code&gt;cryptography&lt;/code&gt;&lt;/a&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; python -m pip install cryptography
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;To illustrate, pretend that you have some sensitive cardholder data (CD) that you never want to have sitting around in plaintext on any server, no matter what.  Before caching it in Redis, you can serialize the data and then encrypt the serialized string using &lt;a href=&quot;https://cryptography.io/en/latest/fernet/&quot;&gt;Fernet&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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;json&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;cryptography.fernet&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Fernet&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;cipher&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Fernet&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Fernet&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;generate_key&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;info&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;s2&quot;&gt;&amp;quot;cardnum&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2211849528391929&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;s2&quot;&gt;&amp;quot;exp&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;mi&quot;&gt;2020&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;gp&quot;&gt;... &lt;/span&gt;    &lt;span class=&quot;s2&quot;&gt;&amp;quot;cv2&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;842&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;n&quot;&gt;r&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;span class=&quot;gp&quot;&gt;... &lt;/span&gt;    &lt;span class=&quot;s2&quot;&gt;&amp;quot;user:1000&amp;quot;&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;cipher&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;json&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dumps&lt;/span&gt;&lt;span class=&quot;p&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;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;encode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;utf-8&amp;quot;&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;n&quot;&gt;r&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;user:1000&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;b&amp;#39;gAAAAABcg8-LfQw9TeFZ1eXbi&amp;#39;  # ... [truncated]&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;cipher&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;decrypt&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;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;user:1000&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;b&amp;#39;{&amp;quot;cardnum&amp;quot;: 2211849528391929, &amp;quot;exp&amp;quot;: [2020, 9], &amp;quot;cv2&amp;quot;: 842}&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;json&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;loads&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cipher&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;decrypt&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;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;user:1000&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)))&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;{&amp;#39;cardnum&amp;#39;: 2211849528391929, &amp;#39;exp&amp;#39;: [2020, 9], &amp;#39;cv2&amp;#39;: 842}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Because &lt;code&gt;info&lt;/code&gt; contains a value that is a &lt;code&gt;list&lt;/code&gt;, you&amp;rsquo;ll need to serialize this into a string that&amp;rsquo;s acceptable by Redis.  (You could use &lt;code&gt;json&lt;/code&gt;, &lt;code&gt;yaml&lt;/code&gt;, or any other serialization for this.)  Next, you encrypt and decrypt that string using the &lt;code&gt;cipher&lt;/code&gt; object.  You need to deserialize the decrypted bytes using &lt;code&gt;json.loads()&lt;/code&gt; so that you can get the result back into the type of your initial input, a &lt;code&gt;dict&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://github.com/fernet/spec/blob/master/Spec.md#token-format&quot;&gt;Fernet&lt;/a&gt; uses AES 128 encryption in CBC mode.  See the &lt;a href=&quot;https://cryptography.io/en/latest/hazmat/primitives/symmetric-encryption/&quot;&gt;&lt;code&gt;cryptography&lt;/code&gt; docs&lt;/a&gt; for an example of using AES 256.  Whatever you choose to do, use &lt;code&gt;cryptography&lt;/code&gt;, not &lt;code&gt;pycrypto&lt;/code&gt; (imported as &lt;code&gt;Crypto&lt;/code&gt;), which is no longer actively maintained.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;If security is paramount, encrypting strings before they make their way across a network connection is never a bad idea.&lt;/p&gt;
&lt;h3 id=&quot;compression&quot;&gt;Compression&lt;/h3&gt;
&lt;p&gt;One last quick optimization is compression.  If bandwidth is a concern or you&amp;rsquo;re cost-conscious, you can implement a lossless compression and decompression scheme when you send and receive data from Redis.  Here&amp;rsquo;s an example using the bzip2 compression algorithm, which in this extreme case cuts down on the number of bytes sent across the connection by a factor of over 2,000:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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;lineno&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;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;bz2&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;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;blob&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;i have a lot to talk about&amp;quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;10000&lt;/span&gt;
&lt;span class=&quot;lineno&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;nb&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;blob&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;encode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;utf-8&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;go&quot;&gt;260000&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;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;# Set the compressed string as value&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 8 &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&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;span class=&quot;s2&quot;&gt;&amp;quot;msg:500&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bz2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;compress&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;blob&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;encode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;utf-8&amp;quot;&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;gp&quot;&gt;&amp;gt;&amp;gt;&amp;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;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;msg:500&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;go&quot;&gt;b&amp;#39;BZh91AY&amp;amp;SY\xdaM\x1eu\x01\x11o\x91\x80@\x002l\x87\&amp;#39;  # ... [truncated]&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;11 &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;len&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;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;msg:500&amp;quot;&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;go&quot;&gt;122&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;13 &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;260_000&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;122&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# Magnitude of savings&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;14 &lt;/span&gt;&lt;span class=&quot;go&quot;&gt;2131.1475409836066&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;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;# Get and decompress the value, then confirm it&amp;#39;s equal to the original&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;17 &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;rblob&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bz2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;decompress&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;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;msg:500&amp;quot;&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;decode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;utf-8&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;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rblob&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;blob&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;19 &lt;/span&gt;&lt;span class=&quot;go&quot;&gt;True&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The way that serialization, encryption, and compression are related here is that they all occur client-side.  You do some operation on the original object on the client-side that ends up making more efficient use of Redis once you send the string over to the server.  The inverse operation then happens again on the client side when you request whatever it was that you sent to the server in the first place.&lt;/p&gt;
&lt;h2 id=&quot;using-hiredis&quot;&gt;Using Hiredis&lt;/h2&gt;
&lt;p&gt;It&amp;rsquo;s common for a client library such as &lt;code&gt;redis-py&lt;/code&gt; to follow a &lt;strong&gt;protocol&lt;/strong&gt; in how it is built.  In this case, &lt;code&gt;redis-py&lt;/code&gt; implements the &lt;a href=&quot;https://redis.io/topics/protocol&quot;&gt;REdis Serialization Protocol&lt;/a&gt;, or RESP.&lt;/p&gt;
&lt;p&gt;Part of fulfilling this protocol consists of converting some Python object in a raw bytestring, sending it to the Redis server, and parsing the response back into an intelligible Python object.&lt;/p&gt;
&lt;p&gt;For example, the string response &amp;ldquo;OK&amp;rdquo; would come back as &lt;code&gt;&quot;+OK\r\n&quot;&lt;/code&gt;, while the integer response 1000 would come back as &lt;code&gt;&quot;:1000\r\n&quot;&lt;/code&gt;.  This can get more complex with other data types such as &lt;a href=&quot;https://redis.io/topics/protocol#resp-arrays&quot;&gt;RESP arrays&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;A &lt;strong&gt;parser&lt;/strong&gt; is a tool in the request-response cycle that interprets this raw response and crafts it into something recognizable to the client.  &lt;code&gt;redis-py&lt;/code&gt; ships with its own parser class, &lt;code&gt;PythonParser&lt;/code&gt;, which does the parsing in pure Python.  (See &lt;a href=&quot;https://github.com/andymccurdy/redis-py/blob/cfa2bc9/redis/connection.py#L289&quot;&gt;&lt;code&gt;.read_response()&lt;/code&gt;&lt;/a&gt; if you&amp;rsquo;re curious.)&lt;/p&gt;
&lt;p&gt;However, there&amp;rsquo;s also a C library, &lt;a href=&quot;https://github.com/redis/hiredis&quot;&gt;Hiredis&lt;/a&gt;, that contains a fast parser that can offer significant speedups for some Redis commands such as &lt;code&gt;LRANGE&lt;/code&gt;.  You can think of Hiredis as an optional accelerator that it doesn&amp;rsquo;t hurt to have around in niche cases.&lt;/p&gt;
&lt;p&gt;All that you have to do to enable &lt;code&gt;redis-py&lt;/code&gt; to use the Hiredis parser is to install its Python bindings in the same environment as &lt;code&gt;redis-py&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 -m pip install hiredis
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;What you&amp;rsquo;re actually installing here is &lt;a href=&quot;https://github.com/redis/hiredis-py&quot;&gt;&lt;code&gt;hiredis-py&lt;/code&gt;&lt;/a&gt;, which is a Python wrapper for a portion of the &lt;a href=&quot;https://github.com/redis/hiredis&quot;&gt;&lt;code&gt;hiredis&lt;/code&gt;&lt;/a&gt; C library.&lt;/p&gt;
&lt;p&gt;The nice thing is that you don&amp;rsquo;t really need to call &lt;code&gt;hiredis&lt;/code&gt; yourself.  Just &lt;code&gt;pip install&lt;/code&gt; it, and this will let &lt;code&gt;redis-py&lt;/code&gt; see that it&amp;rsquo;s available and use its &lt;code&gt;HiredisParser&lt;/code&gt; instead of &lt;code&gt;PythonParser&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Internally, &lt;code&gt;redis-py&lt;/code&gt; will attempt to import &lt;code&gt;hiredis&lt;/code&gt;, and use a &lt;code&gt;HiredisParser&lt;/code&gt; class to match it, but will fall back to its &lt;code&gt;PythonParser&lt;/code&gt; instead, which may be slower in some cases:&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;# redis/utils.py&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;try&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;hiredis&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;HIREDIS_AVAILABLE&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;k&quot;&gt;except&lt;/span&gt; &lt;span class=&quot;ne&quot;&gt;ImportError&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;HIREDIS_AVAILABLE&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;c1&quot;&gt;# redis/connection.py&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;HIREDIS_AVAILABLE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;DefaultParser&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;HiredisParser&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;n&quot;&gt;DefaultParser&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PythonParser&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id=&quot;using-enterprise-redis-applications&quot;&gt;Using Enterprise Redis Applications&lt;/h2&gt;
&lt;p&gt;While Redis itself is open-source and free, several managed services have sprung up that offer a data store with Redis as the core and some additional features built on top of the open-source Redis server:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://docs.aws.amazon.com/AmazonElastiCache/latest/red-ug/WhatIs.html&quot;&gt;&lt;strong&gt;Amazon ElastiCache for Redis&lt;/strong&gt;&lt;/a&gt;&lt;strong&gt;:&lt;/strong&gt; This is a web service that lets you host a Redis server in the cloud, which you can connect to from an Amazon EC2 instance.  For full setup instructions, you can walk through Amazon&amp;rsquo;s &lt;a href=&quot;https://docs.aws.amazon.com/AmazonElastiCache/latest/red-ug/GettingStarted.CreateCluster.html&quot;&gt;ElastiCache for Redis&lt;/a&gt; launch page.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://azure.microsoft.com/en-us/services/cache/&quot;&gt;&lt;strong&gt;Microsoft&amp;rsquo;s Azure Cache for Redis&lt;/strong&gt;&lt;/a&gt;&lt;strong&gt;:&lt;/strong&gt; This is another capable enterprise-grade service that lets you set up a customizable, secure Redis instance in the cloud.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The designs of the two have some commonalities.  You typically specify a custom name for your cache, which is embedded as part of a DNS name, such as &lt;code&gt;demo.abcdef.xz.0009.use1.cache.amazonaws.com&lt;/code&gt; (AWS) or &lt;code&gt;demo.redis.cache.windows.net&lt;/code&gt; (Azure).&lt;/p&gt;
&lt;p&gt;Once you&amp;rsquo;re set up, here are a few quick tips on how to connect.&lt;/p&gt;
&lt;p&gt;From the command line, it&amp;rsquo;s largely the same as in our earlier examples, but you&amp;rsquo;ll need to specify a host with the &lt;code&gt;h&lt;/code&gt; flag rather than using the default localhost.  For &lt;strong&gt;Amazon AWS&lt;/strong&gt;, execute the following from your instance shell:&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;export&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;REDIS_ENDPOINT&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;demo.abcdef.xz.0009.use1.cache.amazonaws.com&amp;quot;&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; redis-cli -h &lt;span class=&quot;nv&quot;&gt;$REDIS_ENDPOINT&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;For &lt;strong&gt;Microsoft Azure&lt;/strong&gt;, you can use a similar call.  Azure Cache for Redis &lt;a href=&quot;https://docs.microsoft.com/en-us/azure/azure-cache-for-redis/cache-how-to-redis-cli-tool&quot;&gt;uses SSL&lt;/a&gt; (port 6380) by default rather than port 6379, allowing for encrypted communication to and from Redis, which can&amp;rsquo;t be said of TCP.  All that you&amp;rsquo;ll need to supply in addition is a non-default port and access key:&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;export&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;REDIS_ENDPOINT&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;demo.redis.cache.windows.net&amp;quot;&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; redis-cli -h &lt;span class=&quot;nv&quot;&gt;$REDIS_ENDPOINT&lt;/span&gt; -p &lt;span class=&quot;m&quot;&gt;6380&lt;/span&gt; -a &amp;lt;primary-access-key&amp;gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;-h&lt;/code&gt; flag specifies a host, which as you&amp;rsquo;ve seen is &lt;code&gt;127.0.0.1&lt;/code&gt; (localhost) by default.&lt;/p&gt;
&lt;p&gt;When you&amp;rsquo;re using &lt;code&gt;redis-py&lt;/code&gt; in Python, it&amp;rsquo;s always a good idea to keep sensitive variables out of Python scripts themselves, and to be careful about what read and write permissions you afford those files.  The Python version would look like this:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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;os&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;redis&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;# Specify a DNS endpoint instead of the default localhost&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;os&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;environ&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;REDIS_ENDPOINT&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;&amp;#39;demo.abcdef.xz.0009.use1.cache.amazonaws.com&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;r&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;redis&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Redis&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;host&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&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;environ&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;REDIS_ENDPOINT&amp;quot;&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 all there is to it.  Besides specifying a different &lt;code&gt;host&lt;/code&gt;, you can now call command-related methods such as &lt;code&gt;r.get()&lt;/code&gt; as normal.&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 you want to use solely the combination of &lt;code&gt;redis-py&lt;/code&gt; and an AWS or Azure Redis instance, then you don&amp;rsquo;t really need to install and make Redis itself locally on your machine, since you don&amp;rsquo;t need either &lt;code&gt;redis-cli&lt;/code&gt; or &lt;code&gt;redis-server&lt;/code&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;If you&amp;rsquo;re deploying a medium- to large-scale production application where Redis plays a key role, then going with AWS or Azure&amp;rsquo;s service solutions can be a scalable, cost-effective, and security-conscious way to operate.&lt;/p&gt;
&lt;h2 id=&quot;wrapping-up&quot;&gt;Wrapping Up&lt;/h2&gt;
&lt;p&gt;That concludes our whirlwind tour of accessing Redis through Python, including installing and using the Redis REPL connected to a Redis server and using &lt;code&gt;redis-py&lt;/code&gt; in real-life examples.  Here&amp;rsquo;s some of what you learned:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;redis-py&lt;/code&gt; lets you do (almost) everything that you can do with the Redis CLI through an intuitive Python API.&lt;/li&gt;
&lt;li&gt;Mastering topics such as persistence, serialization, encryption, and compression lets you use Redis to its full potential.&lt;/li&gt;
&lt;li&gt;Redis transactions and pipelines are essential parts of the library in more complex situations.&lt;/li&gt;
&lt;li&gt;Enterprise-level Redis services can help you smoothly use Redis in production.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Redis has an extensive set of features, some of which we didn&amp;rsquo;t really get to cover here, including &lt;a href=&quot;https://redis.io/commands/eval&quot;&gt;server-side Luda scripting&lt;/a&gt;, &lt;a href=&quot;https://redis.io/topics/partitioning&quot;&gt;sharding&lt;/a&gt;, and &lt;a href=&quot;https://redis.io/topics/replication&quot;&gt;master-slave replication&lt;/a&gt;.  If you think that Redis is up your alley, then make sure to follow developments as it implements an &lt;a href=&quot;http://antirez.com/news/125&quot;&gt;updated protocol, RESP3&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;further-reading&quot;&gt;Further Reading&lt;/h2&gt;
&lt;p&gt;Here are some resources that you can check out to learn more.&lt;/p&gt;
&lt;p&gt;Books:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Josiah Carlson:&lt;/strong&gt; &lt;a href=&quot;https://realpython.com/asins/1617290858/&quot;&gt;&lt;em&gt;Redis in Action&lt;/em&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Karl Seguin:&lt;/strong&gt; &lt;a href=&quot;https://www.openmymind.net/2012/1/23/The-Little-Redis-Book/&quot;&gt;&lt;em&gt;The Little Redis Book&lt;/em&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Luc Perkins et. al.:&lt;/strong&gt; &lt;a href=&quot;https://realpython.com/asins/1680502530/&quot;&gt;&lt;em&gt;Seven Databases in Seven Weeks&lt;/em&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Redis in use:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Twitter:&lt;/strong&gt; &lt;a href=&quot;https://www.infoq.com/presentations/Real-Time-Delivery-Twitter&quot;&gt;Real-Time Delivery Architecture at Twitter&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Spool:&lt;/strong&gt; &lt;a href=&quot;https://blog.getspool.com/2011/11/29/fast-easy-realtime-metrics-using-redis-bitmaps/&quot;&gt;Redis bitmaps – Fast, easy, realtime metrics&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;3scale:&lt;/strong&gt; &lt;a href=&quot;http://tech.3scale.net/2012/07/25/fun-with-redis-replication&quot;&gt;Having fun with Redis Replication between Amazon and Rackspace&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Instagram:&lt;/strong&gt; &lt;a href=&quot;https://instagram-engineering.com/storing-hundreds-of-millions-of-simple-key-value-pairs-in-redis-1091ae80f74c&quot;&gt;Storing hundreds of millions of simple key-value pairs in Redis&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Craigslist:&lt;/strong&gt; &lt;a href=&quot;https://blog.zawodny.com/2011/02/26/redis-sharding-at-craigslist/&quot;&gt;Redis Sharding at Craigslist&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Disqus:&lt;/strong&gt; &lt;a href=&quot;https://github.com/bretthoerner/blog/blob/master/2011/2/21/redis-at-disqus.rst&quot;&gt;Redis at Disqus&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Other:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Digital Ocean:&lt;/strong&gt; &lt;a href=&quot;https://www.digitalocean.com/community/tutorials/how-to-install-and-secure-redis-on-ubuntu-18-04&quot;&gt;How To Secure Your Redis Installation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;AWS:&lt;/strong&gt; &lt;a href=&quot;https://docs.aws.amazon.com/AmazonElastiCache/latest/red-ug/WhatIs.html&quot;&gt;ElastiCache for Redis User Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Microsoft:&lt;/strong&gt; &lt;a href=&quot;https://azure.microsoft.com/en-us/services/cache/&quot;&gt;Azure Cache for Redis&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cheatography:&lt;/strong&gt; &lt;a href=&quot;https://www.cheatography.com/tasjaevan/cheat-sheets/redis/&quot;&gt;Redis Cheat Sheet&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ClassDojo:&lt;/strong&gt; &lt;a href=&quot;https://engineering.classdojo.com/blog/2015/02/06/rolling-rate-limiter/&quot;&gt;Better Rate Limiting With Redis Sorted Sets&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;antirez (Salvatore Sanfilippo):&lt;/strong&gt; &lt;a href=&quot;http://oldblog.antirez.com/post/redis-persistence-demystified.html&quot;&gt;Redis persistence demystified&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Martin Kleppmann:&lt;/strong&gt; &lt;a href=&quot;https://martin.kleppmann.com/2016/02/08/how-to-do-distributed-locking.html&quot;&gt;How to do distributed locking&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;HighScalability:&lt;/strong&gt; &lt;a href=&quot;http://highscalability.com/blog/2011/7/6/11-common-web-use-cases-solved-in-redis.html&quot;&gt;11 Common Web Use Cases Solved in Redis&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>Python Community Interview With Katrina Durance</title>
      <id>https://realpython.com/interview-katrina-durance/</id>
      <link href="https://realpython.com/interview-katrina-durance/"/>
      <updated>2019-06-26T14:00:00+00:00</updated>
      <summary>PyCon US can be a unique experience for anyone, let alone a first-timer. We caught up with a first-time PyCon US attendee, Katrina Durance, to learn about her experience and how it will influence the code she writes going forward.</summary>
      <content type="html">
        &lt;p&gt;With PyCon US 2019 over, I decided to catch up with a PyCon first-timer, &lt;a href=&quot;https://twitter.com/katdurance&quot;&gt;Katrina Durance&lt;/a&gt;. I was curious to see how she found the experience and what her highlights were. I also wanted to understand how attending a conference like PyCon influenced her programming chops.&lt;/p&gt;
&lt;p class=&quot;mt-5&quot;&gt;&lt;strong&gt;Ricky:&lt;/strong&gt; &lt;em&gt;Let&amp;rsquo;s start with the same questions I ask all my guests. How&amp;rsquo;d you get into programming? When did you start using Python?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://files.realpython.com/media/katrina.53ae3d40cad6.jpg&quot; target=&quot;_blank&quot;&gt;&lt;img class=&quot;img-fluid w-25 float-right ml-3&quot; src=&quot;https://files.realpython.com/media/katrina.53ae3d40cad6.jpg&quot; width=&quot;964&quot; height=&quot;1280&quot; srcset=&quot;https://robocrop.realpython.net/?url=https%3A//files.realpython.com/media/katrina.53ae3d40cad6.jpg&amp;amp;w=241&amp;amp;sig=70479e139513bd914f135569dcca1cf8ef1e4f54 241w, https://robocrop.realpython.net/?url=https%3A//files.realpython.com/media/katrina.53ae3d40cad6.jpg&amp;amp;w=482&amp;amp;sig=181a0844338d1269057e64eabc6cf2f68f84b7be 482w, https://files.realpython.com/media/katrina.53ae3d40cad6.jpg 964w&quot; sizes=&quot;75vw&quot; alt=&quot;Katrina Durance&quot;/&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Katrina:&lt;/strong&gt; Python was my first programming course in grad school back in 2013. I also learned R and SQL. The two jobs I&amp;rsquo;ve been in since I graduated have been completely SQL-focused, so Python and R fell by the wayside. &lt;/p&gt;
&lt;p&gt;Since I work at an arts college in Chicago (Columbia College Chicago) I&amp;rsquo;m able to take courses for free. We have a gaming program so all our programming courses are game related. Since I&amp;rsquo;m a gamer and a very visual learner, I decided to take a C# course where we worked on building small games. I liked it. &lt;/p&gt;
&lt;p&gt;I really struggled a lot with Python when I first learned it, but working with a programming language in a visual context started to clarify a lot of concepts for me. I knew after that course that I wanted to build my skills to get into full-time programming. I eventually came up with a study plan and decided to return to my Python roots at the beginning of this year.&lt;/p&gt;
&lt;p class=&quot;mt-5&quot;&gt;&lt;strong&gt;Ricky:&lt;/strong&gt; &lt;em&gt;This year you attended PyCon US for the first time. I&amp;rsquo;m curious why this year was your first. What changed or made you want to go this time around?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Katrina:&lt;/strong&gt; What really clinched it was knowing that there was going to be a group from &lt;a href=&quot;https://www.pythonistacafe.com/&quot;&gt;PythonistaCafe&lt;/a&gt;, and a big contingent from the &lt;a href=&quot;https://www.chipy.org/&quot;&gt;Chicago Python User Group&lt;/a&gt; meetup there. So I knew I would see some friendly faces. I didn&amp;rsquo;t feel I was doing it all alone.&lt;/p&gt;
&lt;p class=&quot;mt-5&quot;&gt;&lt;strong&gt;Ricky:&lt;/strong&gt; &lt;em&gt;Everyone&amp;rsquo;s PyCon experience is different. I&amp;rsquo;m wondering if you had a standout moment this year? Is there one thing that you&amp;rsquo;ll remember synonymously with your first PyCon experience?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Katrina:&lt;/strong&gt; The mentored sprints were a big deal for me. I ended up working on an issue on a tool (&lt;a href=&quot;https://pypi.org/project/hypothesis/&quot;&gt;Hypothesis&lt;/a&gt;) that I didn&amp;rsquo;t understand because I haven&amp;rsquo;t learned much about testing at all yet. &lt;/p&gt;
&lt;p&gt;I was feeling frustrated and concerned that everything would go over my head. But our mentor was amazing and so encouraging and showed me a bunch of things I was learning and kept me going to the end. Now I have a closed issue on the software with my name on it, which is pretty cool.&lt;/p&gt;
&lt;p class=&quot;mt-5&quot;&gt;&lt;strong&gt;Ricky:&lt;/strong&gt; &lt;em&gt;We, of course, met face to face several times over the weekend. But most notably at the PythonistaCafe open space. How was your open space experience? Did you learn anything new, or were there any actionable takeaways?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Katrina:&lt;/strong&gt; I was excited about the PythonistaCafe open space because of the chance to meet some of the folks I&amp;rsquo;ve interacted with or just seen on the forum, and I wasn&amp;rsquo;t disappointed. &lt;/p&gt;
&lt;p&gt;I hosted an open space for self-taught programmers like me. I was stunned when 30-ish people showed up. I did my best to manage it and got some positive feedback and helpful advice. &lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;https://realpython.com/interview-marlene-mhangami/&quot;&gt;PyCon Africa&lt;/a&gt; meetup was very enlightening because I learned that the reason we&amp;rsquo;re not seeing a boom in innovation from Africa yet is that the internet is prohibitively expensive in every country represented in the room. It didn&amp;rsquo;t matter if it was government regulated or privately owned. I would love to help figure out how to solve that problem. &lt;/p&gt;
&lt;figure class=&quot;figure mx-auto d-block&quot;&gt;&lt;a href=&quot;https://www.pythonistacafe.com/&quot; target=&quot;_blank&quot;&gt;&lt;img class=&quot;img-fluid mx-auto d-block &quot; src=&quot;https://files.realpython.com/media/pythonistacafe-pycon-openspace.b0db2583111e.jpg&quot; width=&quot;1920&quot; height=&quot;1080&quot; srcset=&quot;https://robocrop.realpython.net/?url=https%3A//files.realpython.com/media/pythonistacafe-pycon-openspace.b0db2583111e.jpg&amp;amp;w=480&amp;amp;sig=fdcbeeb5f204294026e3874d23c07e48a9b95322 480w, https://robocrop.realpython.net/?url=https%3A//files.realpython.com/media/pythonistacafe-pycon-openspace.b0db2583111e.jpg&amp;amp;w=960&amp;amp;sig=e605065d341332bf82b9e75ee52d75047a64c9c7 960w, https://files.realpython.com/media/pythonistacafe-pycon-openspace.b0db2583111e.jpg 1920w&quot; sizes=&quot;75vw&quot; alt=&quot;Pyhtonista Cafe Open Space - Pycon&quot;/&gt;&lt;/a&gt;&lt;figcaption class=&quot;figure-caption text-center&quot;&gt;PythonistaCafe Members Coming Together at a PyCon Open Space&lt;/figcaption&gt;&lt;/figure&gt;

&lt;p class=&quot;mt-5&quot;&gt;&lt;strong&gt;Ricky:&lt;/strong&gt; &lt;em&gt;There is so much to do at PyCon that there&amp;rsquo;s just not enough time to do it all. So was there anything you wish you had done or a talk you&amp;rsquo;d missed that you wish you hadn&amp;rsquo;t? Anything you&amp;rsquo;d do differently next time?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Katrina:&lt;/strong&gt; I felt PyCon was what I was hoping it would be for this first time around, to be honest. Next year I want to stay for the sprints, which people kept telling me were amazing.&lt;/p&gt;
&lt;p class=&quot;mt-5&quot;&gt;&lt;strong&gt;Ricky:&lt;/strong&gt; &lt;em&gt;So for those reading this that have yet to go to their first PyCon, this might be the most important question… How did attending PyCon affect how you will write your Python code going forward?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Katrina:&lt;/strong&gt; I had to talk about my code. When you&amp;rsquo;re self-taught, you don&amp;rsquo;t get a lot of opportunities to talk through your code. Through the conversations I had at PyCon, I was encouraged to be more deliberate about taking advantage of my Slack and local Python communities to practice those communication skills. &lt;/p&gt;
&lt;p&gt;In other words, I need to notch up my courage and not worry if I&amp;rsquo;m not coding it or explaining it well yet. I just need to keep coding and explaining.&lt;/p&gt;
&lt;p class=&quot;mt-5&quot;&gt;&lt;strong&gt;Ricky:&lt;/strong&gt; &lt;em&gt;Last but not least, what else do you get up to in your spare time? What other hobbies and interests do you have, aside from Python and coding? Anything you&amp;rsquo;d like to plug?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Katrina:&lt;/strong&gt; I love all things Sci-Fi and weird: movies, TV series, books, etc. I&amp;rsquo;m a LEGO enthusiast and have a penchant for building lost temples out of my love for H. P. Lovecraft stories. I really like VR and enjoy playing games on my Oculus Go. I also make jewelry out of felt, found objects, or even LEGO pieces.&lt;/p&gt;
&lt;p class=&quot;mt-5&quot;&gt;If you&amp;rsquo;d like to catch up with Katrina and say &lt;em&gt;hi&lt;/em&gt;, drop her a message on &lt;a href=&quot;https://twitter.com/katdurance&quot;&gt;Twitter&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If there&amp;rsquo;s someone from the Python community that you&amp;rsquo;d love me to interview, leave a comment below and let me know.&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>Generating Random Data in Python</title>
      <id>https://realpython.com/courses/generating-random-data-python/</id>
      <link href="https://realpython.com/courses/generating-random-data-python/"/>
      <updated>2019-06-25T14:00:00+00:00</updated>
      <summary>In this course, you&#39;ll cover several options for generating random data in Python, and then build up to a comparison of each in terms of its level of security, versatility, purpose, and speed.</summary>
      <content type="html">
        &lt;p&gt;In this course, you&amp;rsquo;ll cover several options for generating random data in Python, and then build up to a comparison of each in terms of its level of security, versatility, purpose, 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>Basic Input, Output, and String Formatting in Python</title>
      <id>https://realpython.com/python-input-output/</id>
      <link href="https://realpython.com/python-input-output/"/>
      <updated>2019-06-24T14:00:00+00:00</updated>
      <summary>In this step-by-step Python tutorial, you&#39;ll learn how to take user input from the keyboard with the built-in function input(), how to display output to the console with the built-in function print(), and how to format string data with the string modulo operator.</summary>
      <content type="html">
        &lt;p&gt;To be useful, a program usually needs to communicate with the outside world by obtaining input data from the user and displaying result data back to the user.  This tutorial will introduce you to Python input and output.&lt;/p&gt;
&lt;p&gt;Input may come directly from the user via the keyboard, or from some external source like a file or database.  Output can be displayed directly to the console or IDE, to the screen via a Graphical User Interface (GUI), or again to an external source.&lt;/p&gt;
&lt;p&gt;In the &lt;a href=&quot;https://realpython.com/python-for-loop/&quot;&gt;previous tutorial&lt;/a&gt; in this introductory series, you:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Saw a comparison of some different paradigms used by programming languages to implement definite iteration&lt;/li&gt;
&lt;li&gt;Learned about iterables and iterators, two concepts that form the basis of definite iteration in Python&lt;/li&gt;
&lt;li&gt;Tied it all together to learn about Python’s for loops&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;By the end of this tutorial, you&amp;rsquo;ll know how to:&lt;/strong&gt; &lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Take user input from the keyboard with the built-in function &lt;strong&gt;&lt;code&gt;input()&lt;/code&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Display output to the console with the built-in function &lt;strong&gt;&lt;code&gt;print()&lt;/code&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Format string data with the &lt;strong&gt;string modulo operator&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Without further ado, let&amp;rsquo;s dive in!&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-shortened&quot; data-focus=&quot;false&quot;&gt;Click here to get a Python Cheat Sheet&lt;/a&gt; and learn 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;reading-input-from-the-keyboard&quot;&gt;Reading Input From the Keyboard&lt;/h2&gt;
&lt;p&gt;Programs often need to obtain data from the user, usually by way of input from the keyboard.  The simplest way to accomplish this in Python is with &lt;code&gt;input()&lt;/code&gt;.&lt;/p&gt;
&lt;p class=&quot;h4 mt-5&quot;&gt;&lt;code&gt;input([&amp;lt;prompt&amp;gt;])&lt;/code&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Reads a line of input from the keyboard.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;code&gt;input()&lt;/code&gt; pauses program execution to allow the user to type in a line of input from the keyboard.  Once the user presses the &lt;span class=&quot;keys&quot;&gt;&lt;kbd class=&quot;key-enter&quot;&gt;Enter&lt;/kbd&gt;&lt;/span&gt; key, all characters typed are read and returned as a string:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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;s&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;foo bar baz&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;s&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;&amp;#39;foo bar baz&amp;#39;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Note that the newline generated when the user presses the &lt;span class=&quot;keys&quot;&gt;&lt;kbd class=&quot;key-enter&quot;&gt;Enter&lt;/kbd&gt;&lt;/span&gt; key isn&amp;rsquo;t included as part of the return string.&lt;/p&gt;
&lt;p&gt;If you include the optional &lt;code&gt;&amp;lt;prompt&amp;gt;&lt;/code&gt; argument, &lt;code&gt;input()&lt;/code&gt; displays it as a prompt to the user before pausing to read input:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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;nb&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;What is your name? &amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;What is your name? Winston Smith&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;Winston Smith&amp;#39;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;code&gt;input()&lt;/code&gt; always returns a string.  If you want a numeric type, then you need to convert the string to the appropriate type with the &lt;code&gt;int()&lt;/code&gt;, &lt;code&gt;float()&lt;/code&gt;, or &lt;code&gt;complex()&lt;/code&gt; built-in functions:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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;lineno&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;n&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;Enter a number: &amp;#39;&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;go&quot;&gt;Enter a number: 50&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 3 &lt;/span&gt;&lt;span class=&quot;hll&quot;&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;n&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&gt;&lt;span class=&quot;lineno&quot;&gt; 4 &lt;/span&gt;&lt;span class=&quot;gt&quot;&gt;Traceback (most recent call last):&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 5 &lt;/span&gt;  File &lt;span class=&quot;nb&quot;&gt;&amp;quot;&amp;lt;stdin&amp;gt;&amp;quot;&lt;/span&gt;, line &lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;, in &lt;span class=&quot;n&quot;&gt;&amp;lt;module&amp;gt;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 6 &lt;/span&gt;&lt;span class=&quot;gr&quot;&gt;TypeError&lt;/span&gt;: &lt;span class=&quot;n&quot;&gt;must be str, not int&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;hll&quot;&gt;&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;n&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;Enter a number: &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; 9 &lt;/span&gt;&lt;span class=&quot;go&quot;&gt;Enter a number: 50&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;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;n&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&gt;&lt;span class=&quot;lineno&quot;&gt;11 &lt;/span&gt;&lt;span class=&quot;go&quot;&gt;150&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In the example above, the expression &lt;code&gt;n + 100&lt;/code&gt; on line 3 is invalid because &lt;code&gt;n&lt;/code&gt; is a string and &lt;code&gt;100&lt;/code&gt; is an integer.  Line 8 converts &lt;code&gt;n&lt;/code&gt; to an integer so the &lt;code&gt;print()&lt;/code&gt; statement on line 10 succeeds.&lt;/p&gt;
&lt;div class=&quot;alert alert-primary&quot; role=&quot;alert&quot;&gt;
&lt;p&gt;&lt;strong&gt;Python Version Note:&lt;/strong&gt;  Should you find yourself working with Python 2.x code, you might bump into a slight difference in the input functions between Python versions 2 and 3.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;raw_input()&lt;/code&gt; in Python 2 reads input from the keyboard and returns it. &lt;code&gt;raw_input()&lt;/code&gt; in Python 2 behaves just like &lt;code&gt;input()&lt;/code&gt; in Python 3, as described above.&lt;/p&gt;
&lt;p&gt;But Python 2 also has a function called &lt;code&gt;input()&lt;/code&gt;.  In Python 2, &lt;code&gt;input()&lt;/code&gt; reads input from the keyboard, &lt;em&gt;parses and evaluates it as a Python expression&lt;/em&gt;, and then returns the resulting value.&lt;/p&gt;
&lt;p&gt;Python 3 does not provide a single function that does exactly what Python 2&amp;rsquo;s &lt;code&gt;input()&lt;/code&gt; does.  The effect can be mimicked in Python 3 with the expression &lt;code&gt;eval(input())&lt;/code&gt;.  However, this is considered a security risk because it allows a user to run arbitrary, potentially malicious code.&lt;/p&gt;
&lt;p&gt;See the &lt;a href=&quot;https://docs.python.org/3/library/functions.html#eval&quot;&gt;Python documentation&lt;/a&gt; for more information on &lt;code&gt;eval()&lt;/code&gt;, and the &lt;a href=&quot;https://en.wikipedia.org/wiki/Eval&quot;&gt;Wikipedia &lt;code&gt;eval&lt;/code&gt; page&lt;/a&gt; for a discussion of potential security risks.&lt;/p&gt;
&lt;/div&gt;
&lt;h2 id=&quot;writing-output-to-the-console&quot;&gt;Writing Output to the Console&lt;/h2&gt;
&lt;p&gt;In addition to obtaining data from the user, a program will also usually need to present data back to the user.  You can display program data to the console in Python with &lt;code&gt;print()&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;unformatted-console-output&quot;&gt;Unformatted Console Output&lt;/h3&gt;
&lt;p&gt;To display objects to the console, pass them as a comma-separated list of argument to &lt;code&gt;print()&lt;/code&gt;.&lt;/p&gt;
&lt;p class=&quot;h4 mt-5&quot;&gt;&lt;code&gt;print(&amp;lt;obj&amp;gt;, ..., &amp;lt;obj&amp;gt;)&lt;/code&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Displays a string representation of each &lt;code&gt;&amp;lt;obj&amp;gt;&lt;/code&gt; to the console.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;By default, &lt;code&gt;print()&lt;/code&gt; separates each object by a single space and appends a newline to the end of the output:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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;fname&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;Winston&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;lname&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;Smith&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;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;Name:&amp;#39;&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;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lname&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Name: Winston Smith&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Any type of object can be specified as an argument to &lt;code&gt;print()&lt;/code&gt;.  If an object isn&amp;rsquo;t a string, then &lt;code&gt;print()&lt;/code&gt; converts it to an appropriate string representation displaying it:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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;a&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;mi&quot;&gt;2&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;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;&amp;lt;class &amp;#39;list&amp;#39;&amp;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;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;12&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;type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;&amp;lt;class &amp;#39;int&amp;#39;&amp;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;d&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;foo&amp;#39;&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;s1&quot;&gt;&amp;#39;bar&amp;#39;&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;type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;&amp;lt;class &amp;#39;dict&amp;#39;&amp;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;type&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;go&quot;&gt;&amp;lt;class &amp;#39;builtin_function_or_method&amp;#39;&amp;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;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;d&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;go&quot;&gt;[1, 2, 3] -12 {&amp;#39;foo&amp;#39;: 1, &amp;#39;bar&amp;#39;: 2} &amp;lt;built-in function len&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;As you can see, even complex types like lists, dictionaries, and functions can be displayed to the console with &lt;code&gt;print()&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;keyword-arguments-to-print&quot;&gt;Keyword Arguments to &lt;code&gt;print()&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;print()&lt;/code&gt; takes a few additional arguments that provide modest control over the format of the output.  Each of these is a special type of argument called a &lt;strong&gt;keyword argument&lt;/strong&gt;.  This introductory series of tutorials will include a tutorial on functions and parameter passing so you can learn more about keyword arguments.&lt;/p&gt;
&lt;p&gt;For now, here&amp;rsquo;s what you need to know:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Keyword arguments have the form &lt;code&gt;&amp;lt;keyword&amp;gt;=&amp;lt;value&amp;gt;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Any keyword arguments passed to &lt;code&gt;print()&lt;/code&gt; must come at the end, after the list of objects to display.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In the following sections, you&amp;rsquo;ll see how these keyword arguments affect console output produced by &lt;code&gt;print()&lt;/code&gt;.&lt;/p&gt;
&lt;h4 id=&quot;the-sep-keyword-argument&quot;&gt;The &lt;code&gt;sep=&lt;/code&gt; Keyword Argument&lt;/h4&gt;
&lt;p&gt;Adding the keyword argument &lt;code&gt;sep=&amp;lt;str&amp;gt;&lt;/code&gt; causes objects to be separated by the string &lt;code&gt;&amp;lt;str&amp;gt;&lt;/code&gt; instead of the default single space:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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;foo&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;42&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;bar&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;foo 42 bar&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;foo&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;42&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;bar&amp;#39;&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;/&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;foo/42/bar&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;foo&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;42&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;bar&amp;#39;&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;...&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;foo...42...bar&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;d&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;foo&amp;#39;&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;s1&quot;&gt;&amp;#39;bar&amp;#39;&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;s1&quot;&gt;&amp;#39;baz&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;&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;k&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;items&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;k&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v&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; -&amp;gt; &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;go&quot;&gt;foo -&amp;gt; 1&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;bar -&amp;gt; 2&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;baz -&amp;gt; 3&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;To squish objects together without any space between them, specify &lt;code&gt;sep=&#39;&#39;&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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;foo&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;42&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;bar&amp;#39;&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;&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;foo42bar&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You can specify any arbitrary string as the separator with the &lt;code&gt;sep=&lt;/code&gt; keyword.&lt;/p&gt;
&lt;h4 id=&quot;the-end-keyword-argument&quot;&gt;The &lt;code&gt;end=&lt;/code&gt; Keyword Argument&lt;/h4&gt;
&lt;p&gt;The keyword argument &lt;code&gt;end=&amp;lt;str&amp;gt;&lt;/code&gt; causes output to be terminated by &lt;code&gt;&amp;lt;str&amp;gt;&lt;/code&gt; instead of the default newline:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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;kc&quot;&gt;True&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;s1&quot;&gt;&amp;#39;foo&amp;#39;&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;s1&quot;&gt;&amp;#39;/&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;nb&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;42&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;s1&quot;&gt;&amp;#39;/&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;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;bar&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;go&quot;&gt;foo/42/bar&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;For example, if you are displaying values in a loop, you might use &lt;code&gt;end=&lt;/code&gt; to cause the values to be displayed on one line, rather than on individual lines:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n&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;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;n&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;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;go&quot;&gt;5&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;6&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;7&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;8&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;9&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;n&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;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;n&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;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39; &amp;#39;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;9&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&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;gp&quot;&gt;...&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;0 1 2 3 4 5 6 7 8 9&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Any string may be specified as the output terminator with the &lt;code&gt;end=&lt;/code&gt; keyword.&lt;/p&gt;
&lt;h4 id=&quot;output-stream-keyword-arguments&quot;&gt;Output Stream Keyword Arguments&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;print()&lt;/code&gt; accepts two additional keyword arguments, both of which affect handling of the output stream:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;file=&amp;lt;stream&amp;gt;&lt;/code&gt;:&lt;/strong&gt;  By default, &lt;code&gt;print()&lt;/code&gt; sends its output to a default stream called &lt;code&gt;sys.stdout&lt;/code&gt;, which is usually equivalent to the console.  The &lt;code&gt;file=&amp;lt;stream&amp;gt;&lt;/code&gt; argument causes output to be sent to an alternate stream designated by &lt;code&gt;&amp;lt;stream&amp;gt;&lt;/code&gt; instead.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;flush=True&lt;/code&gt;:&lt;/strong&gt;  Ordinarily, &lt;code&gt;print()&lt;/code&gt; buffers its output and only writes to the output stream intermittently.  &lt;code&gt;flush=True&lt;/code&gt; specifies that the output stream is forcibly flushed with each &lt;code&gt;print()&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;These two keyword arguments are presented here for the sake of completeness.  You probably don&amp;rsquo;t need to be too concerned about output streams at this point.  They are discussed later in this series in the tutorial on File I/O.&lt;/p&gt;
&lt;h2 id=&quot;formatted-string-output&quot;&gt;Formatted String Output&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;print()&lt;/code&gt; supports formatting of console output that is rudimentary at best.  You can choose how to separate printed objects, and you can specify what goes at the end of the printed line.  That&amp;rsquo;s about it.&lt;/p&gt;
&lt;p&gt;In many cases, you&amp;rsquo;ll need more precise control over the appearance of data destined for display.  Python provides several ways to format output string data.  In this section, you&amp;rsquo;ll learn about one of the older ones: the &lt;strong&gt;string modulo operator&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;In recent versions of Python, there are newer ways to format string data that are arguably superior to the string modulo operator: the &lt;strong&gt;string &lt;code&gt;.format()&lt;/code&gt; method&lt;/strong&gt;, and &lt;strong&gt;f-strings&lt;/strong&gt;.  You will learn about these in the next tutorial in this series.  You may also want to check out these articles:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://realpython.com/courses/python-string-formatting-tips-best-practices&quot;&gt;Python String Formatting Tips &amp;amp; Best Practices&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&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;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Though other formatting options are available, the string modulo operator is still widely used.  If you&amp;rsquo;re reading existing Python code, you are likely to encounter the string modulo operator, so it will be beneficial to familiarize yourself with 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; If you&amp;rsquo;re acquainted with the &lt;a href=&quot;https://en.wikipedia.org/wiki/Printf_format_string&quot;&gt;&lt;code&gt;printf()&lt;/code&gt;&lt;/a&gt; family of functions of C, Perl, or Java, then you&amp;rsquo;ll see that these don&amp;rsquo;t exist in Python. However, there is a quite a bit of similarity between &lt;code&gt;printf()&lt;/code&gt; and the string modulo operator, so if you&amp;rsquo;re familiar with &lt;code&gt;printf()&lt;/code&gt;, then a lot of the following will feel familiar.&lt;/p&gt;
&lt;p&gt;On the other hand, if you aren&amp;rsquo;t familiar with &lt;code&gt;printf()&lt;/code&gt;, then don&amp;rsquo;t worry! The following should still make sense.&lt;/p&gt;
&lt;/div&gt;
&lt;h2 id=&quot;the-string-modulo-operator&quot;&gt;The String Modulo Operator&lt;/h2&gt;
&lt;p&gt;The &lt;a href=&quot;https://realpython.com/python-operators-expressions/#arithmetic-operators&quot;&gt;modulo operator&lt;/a&gt; (&lt;code&gt;%&lt;/code&gt;) is usually used with numbers, in which case it computes remainder from division:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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;11&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;go&quot;&gt;2&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;With string operands, the modulo operator has an entirely different function:  string formatting.  (The two operations aren&amp;rsquo;t really much like one another.  They share the same name because they are represented by the same symbol: &lt;code&gt;%&lt;/code&gt;.)&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s what the syntax of the string modulo operator looks 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;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;format_string&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;values&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;On the left side of the &lt;code&gt;%&lt;/code&gt; operator, &lt;code&gt;&amp;lt;format_string&amp;gt;&lt;/code&gt; is a string containing one or more conversion specifiers.  The &lt;code&gt;&amp;lt;values&amp;gt;&lt;/code&gt; on the right side get inserted into &lt;code&gt;&amp;lt;format_string&amp;gt;&lt;/code&gt; in place of the conversion specifiers. The resulting formatted string is the value of the expression.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s get started with an example.  Here&amp;rsquo;s a &lt;code&gt;print()&lt;/code&gt; statement that displays a formatted string using the string modulo operator:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%d&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%s&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt; cost $&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%.2f&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;&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;6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;bananas&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;1.74&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;6 bananas cost $1.74&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In addition to representing the string modulo operation itself, the &lt;code&gt;&#39;%&#39;&lt;/code&gt; character also denotes the conversion specifiers in the format string&amp;mdash;in this case, &lt;code&gt;&#39;%d&#39;&lt;/code&gt;, &lt;code&gt;&#39;%s&#39;&lt;/code&gt;, and &lt;code&gt;&#39;%.2f&#39;&lt;/code&gt;.  &lt;/p&gt;
&lt;p&gt;In the output, each item from the tuple of values is converted to a string value and inserted into the format string in place of the corresponding conversion specifier:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The first item in the tuple is &lt;code&gt;6&lt;/code&gt;, a numeric value that replaces &lt;code&gt;&#39;%d&#39;&lt;/code&gt; in the format string.&lt;/li&gt;
&lt;li&gt;The next item is the string value &lt;code&gt;&#39;bananas&#39;&lt;/code&gt;, which replaces &lt;code&gt;&#39;%s&#39;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The last item is the float value &lt;code&gt;1.74&lt;/code&gt;, which replaces &lt;code&gt;&#39;%.2f&#39;&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The resulting string is &lt;code&gt;6 bananas cost $1.74&lt;/code&gt;, as demonstrated in the following diagram:&lt;/p&gt;
&lt;figure class=&quot;figure mx-auto d-block&quot;&gt;&lt;a href=&quot;https://files.realpython.com/media/t.176c482e3252.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/t.176c482e3252.png&quot; width=&quot;1443&quot; height=&quot;684&quot; srcset=&quot;https://robocrop.realpython.net/?url=https%3A//files.realpython.com/media/t.176c482e3252.png&amp;amp;w=360&amp;amp;sig=68d5ec2944490b9930f4119d43ade440971876e7 360w, https://robocrop.realpython.net/?url=https%3A//files.realpython.com/media/t.176c482e3252.png&amp;amp;w=721&amp;amp;sig=1cb8f5e1d60bd3c6e132f2ce02e73f81cfd7d77f 721w, https://files.realpython.com/media/t.176c482e3252.png 1443w&quot; sizes=&quot;75vw&quot; alt=&quot;Illustration of Python string modulo operator usage&quot;/&gt;&lt;/a&gt;&lt;figcaption class=&quot;figure-caption text-center&quot;&gt;The String Modulo Operator&lt;/figcaption&gt;&lt;/figure&gt;

&lt;p&gt;If there are multiple values to insert, then they must be enclosed in a tuple as illustrated above.  If there is only one value, then it can appear by itself:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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;Hello, my name is &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%s&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;.&amp;#39;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;Graham&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Hello, my name is Graham.&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Notice also that string modulo operation isn&amp;rsquo;t only for printing.  You can also format values and assign them to another string variable:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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;s&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;Hello, my name is &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%s&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;.&amp;#39;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;Graham&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;s&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;&amp;#39;Hello, my name is Graham.&amp;#39;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;(Again, if you are familiar with the functions related to &lt;code&gt;printf()&lt;/code&gt;, then this is reminiscent of &lt;code&gt;sprintf()&lt;/code&gt;.  If you aren&amp;rsquo;t, then don&amp;rsquo;t sweat it.)&lt;/p&gt;
&lt;h3 id=&quot;conversion-specifiers&quot;&gt;Conversion Specifiers&lt;/h3&gt;
&lt;p&gt;Conversion specifiers appear in the &lt;code&gt;&amp;lt;format_string&amp;gt;&lt;/code&gt; and determine how values are formatted when they&amp;rsquo;re inserted.&lt;/p&gt;
&lt;p&gt;A conversion specifier begins with a &lt;code&gt;%&lt;/code&gt; character and consists of these components:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;%[&amp;lt;flags&amp;gt;][&amp;lt;width&amp;gt;][.&amp;lt;precision&amp;gt;]&amp;lt;type&amp;gt;&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;code&gt;%&lt;/code&gt; and &lt;code&gt;&amp;lt;type&amp;gt;&lt;/code&gt; are required.  The remaining components shown in square brackets are optional.&lt;/p&gt;
&lt;p&gt;The following table summarizes what each component of a conversion specifier does:&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;Component&lt;/th&gt;
&lt;th&gt;Meaning&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;%&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Introduces the conversion specifier&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;&amp;lt;flags&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Indicates one or more flags that exert finer control over formatting&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;&amp;lt;width&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Specifies the minimum width of the formatted result&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;.&amp;lt;precision&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Determines the length and precision of floating point or string output&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;&amp;lt;type&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Indicates the type of conversion to be performed&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;p&gt;Read on for more detail on how these work.&lt;/p&gt;
&lt;h3 id=&quot;conversion-type&quot;&gt;Conversion Type&lt;/h3&gt;
&lt;p&gt;The conversion type, &lt;code&gt;&amp;lt;type&amp;gt;&lt;/code&gt;, is the last component of the conversion specifier:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;%[&amp;lt;flags&amp;gt;][&amp;lt;width&amp;gt;][.&amp;lt;precision&amp;gt;]&lt;/code&gt;&lt;strong&gt;&lt;code&gt;&amp;lt;type&amp;gt;&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It determines the type of conversion the corresponding value undergoes before insertion into the format string.  Here&amp;rsquo;s a table that lists the possible conversion types:&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;&amp;lt;type&amp;gt;&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;Conversion Type&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;d&lt;/code&gt;, &lt;code&gt;i&lt;/code&gt;, &lt;code&gt;u&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Decimal integer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;x&lt;/code&gt;, &lt;code&gt;X&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Hexadecimal integer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;o&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Octal integer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;f&lt;/code&gt;, &lt;code&gt;F&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Floating point&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;e&lt;/code&gt;, &lt;code&gt;E&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Exponential&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;g&lt;/code&gt;, &lt;code&gt;G&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Floating point or Exponential&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;c&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Single character&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;s&lt;/code&gt;, &lt;code&gt;r&lt;/code&gt;, &lt;code&gt;a&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;String&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;%&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Single &lt;code&gt;&#39;%&#39;&lt;/code&gt; character&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;p&gt;You&amp;rsquo;ll see how to use these conversion types in the following sections.&lt;/p&gt;
&lt;h4 id=&quot;integer-conversion-types&quot;&gt;Integer Conversion Types&lt;/h4&gt;
&lt;p&gt;The &lt;code&gt;d&lt;/code&gt;, &lt;code&gt;i&lt;/code&gt;, &lt;code&gt;u&lt;/code&gt;, &lt;code&gt;x&lt;/code&gt;, &lt;code&gt;X&lt;/code&gt;, and &lt;code&gt;o&lt;/code&gt; conversion types correspond to integer values.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;d&lt;/code&gt;, &lt;code&gt;i&lt;/code&gt;, and &lt;code&gt;u&lt;/code&gt; are functionally equivalent. They all convert the corresponding argument to a string representation of a decimal integer:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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;s1&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%d&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%i&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%u&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;&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;42&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;42&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;42&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;&amp;#39;42, 42, 42&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;s1&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%d&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%i&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%u&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;&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;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;42&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;42&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;42&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;&amp;#39;-42, -42, -42&amp;#39;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The value can either be positive or negative.  If it is negative, then the resulting value will start with a &lt;code&gt;&#39;-&#39;&lt;/code&gt; character.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;x&lt;/code&gt; and &lt;code&gt;X&lt;/code&gt; convert to a string representation of a hexadecimal integer value, and &lt;code&gt;o&lt;/code&gt; converts to a string representation of an octal integer value:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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;s1&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%x&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%X&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;&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;252&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;252&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;&amp;#39;fc, FC&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;s1&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%o&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;16&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;&amp;#39;20&amp;#39;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;code&gt;x&lt;/code&gt; produces lowercase output, and &lt;code&gt;X&lt;/code&gt; produces uppercase.  (Uppercase &lt;code&gt;&#39;O&#39;&lt;/code&gt; is not a valid conversion type.)&lt;/p&gt;
&lt;p&gt;You can gain some additional control over the resulting format by using &lt;strong&gt;conversion flags&lt;/strong&gt;, which you&amp;rsquo;ll learn more about in an upcoming section.&lt;/p&gt;
&lt;h4 id=&quot;floating-point-conversion-types&quot;&gt;Floating Point Conversion Types&lt;/h4&gt;
&lt;p&gt;Conversion types &lt;code&gt;f&lt;/code&gt; and &lt;code&gt;F&lt;/code&gt; convert to a string representation of a floating point number, while &lt;code&gt;e&lt;/code&gt; and &lt;code&gt;E&lt;/code&gt; produce a string representing exponential (scientific) notation:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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;s1&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%f&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%F&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;&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;mf&quot;&gt;3.14159&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;3.14&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;&amp;#39;3.141590, 3.140000&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;s1&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%e&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%E&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;&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;mf&quot;&gt;1000.0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;1000.0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;&amp;#39;1.000000e+03, 1.000000E+03&amp;#39;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;code&gt;e&lt;/code&gt; produces lowercase output, and &lt;code&gt;E&lt;/code&gt; produces uppercase.&lt;/p&gt;
&lt;blockquote&gt;
&lt;h4 id=&quot;deep-dive-inf-and-nan&quot;&gt;Deep Dive: &lt;code&gt;inf&lt;/code&gt; and &lt;code&gt;NaN&lt;/code&gt;&lt;/h4&gt;
&lt;p&gt;Under some circumstances, a floating-point operation can result in a value that is essentially infinite.  The string representation of such a number in Python is &lt;code&gt;&#39;inf&#39;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;It also may happen that a floating-point operation produces a value that is not representable as a number.  Python represents this with the string &lt;code&gt;&#39;NaN&#39;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;When these values are converted with the string modulo operator, the conversion type character controls the case of the resulting output.  &lt;code&gt;f&lt;/code&gt; and &lt;code&gt;e&lt;/code&gt; produce lowercase output, while &lt;code&gt;F&lt;/code&gt; and &lt;code&gt;E&lt;/code&gt; produce uppercase:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;NaN&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;s1&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%f&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%e&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%F&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%E&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;&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;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;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;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;&amp;#39;nan, nan, NAN, NAN&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;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;Inf&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;s1&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%f&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%e&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%F&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%E&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;&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;y&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;y&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;&amp;#39;inf, inf, INF, INF&amp;#39;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This is the only difference between the &lt;code&gt;f&lt;/code&gt; and &lt;code&gt;F&lt;/code&gt; conversion types.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The &lt;code&gt;g&lt;/code&gt; and &lt;code&gt;G&lt;/code&gt; conversion types choose between floating point or exponential output, depending on the magnitude of the exponent and the value specified for &lt;code&gt;.&amp;lt;precision&amp;gt;&lt;/code&gt;. (See below.)  Output is the same as &lt;code&gt;e&lt;/code&gt;/&lt;code&gt;E&lt;/code&gt; if the exponent is less than &lt;code&gt;-4&lt;/code&gt; or not less than &lt;code&gt;.&amp;lt;precision&amp;gt;&lt;/code&gt;.  Otherwise, it&amp;rsquo;s the same as &lt;code&gt;f&lt;/code&gt;/&lt;code&gt;F&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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;s1&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%g&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;3.14&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;&amp;#39;3.14&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;s1&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%g&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.00000003&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;&amp;#39;3e-08&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;s1&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%G&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.00000003&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;&amp;#39;3E-08&amp;#39;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Basically, you can think of these conversion types as making a &amp;ldquo;reasonable&amp;rdquo; choice.  They&amp;rsquo;ll produce floating point output if the value in question is reasonably suitable for it, and exponential format otherwise.&lt;/p&gt;
&lt;p&gt;Similar to the other floating point conversion types, &lt;code&gt;g&lt;/code&gt; produces lowercase output, and &lt;code&gt;G&lt;/code&gt; produces uppercase.&lt;/p&gt;
&lt;h4 id=&quot;character-conversion-types&quot;&gt;Character Conversion Types&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;c&lt;/code&gt; inserts a single character.  The corresponding value may be either an integer or a single-character string:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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;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;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;97&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;&amp;#39;a&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;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;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;y&amp;#39;&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;&amp;#39;[y]&amp;#39;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;c&lt;/code&gt; conversion type supports conversion to &lt;a href=&quot;https://realpython.com/python-encodings-guide&quot;&gt;Unicode&lt;/a&gt; characters as well:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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;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;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8721&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;&amp;#39;∑&amp;#39;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;code&gt;s&lt;/code&gt;, &lt;code&gt;r&lt;/code&gt;, and &lt;code&gt;a&lt;/code&gt; produce string output using the built-in functions &lt;a href=&quot;https://docs.python.org/3/library/stdtypes.html#str&quot;&gt;&lt;code&gt;str()&lt;/code&gt;&lt;/a&gt;, &lt;a href=&quot;https://docs.python.org/3/library/functions.html#repr&quot;&gt;&lt;code&gt;repr()&lt;/code&gt;&lt;/a&gt;, and &lt;a href=&quot;https://docs.python.org/3/library/functions.html#ascii&quot;&gt;&lt;code&gt;ascii()&lt;/code&gt;&lt;/a&gt;, respectively:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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;s1&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%s&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;foo&amp;#39;&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;&amp;#39;foo&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;s1&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%r&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;foo&amp;#39;&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;&amp;quot;&amp;#39;foo&amp;#39;&amp;quot;&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%a&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;foo&amp;#39;&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;&amp;quot;&amp;#39;foo&amp;#39;&amp;quot;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The justification and padding of string output can be controlled with the &lt;code&gt;&amp;lt;width&amp;gt;&lt;/code&gt; and &lt;code&gt;.&amp;lt;precision&amp;gt;&lt;/code&gt; specifiers, as you will see shortly.&lt;/p&gt;
&lt;h4 id=&quot;inserting-a-character&quot;&gt;Inserting a &lt;code&gt;&#39;%&#39;&lt;/code&gt; Character&lt;/h4&gt;
&lt;p&gt;To insert a literal &lt;code&gt;&#39;%&#39;&lt;/code&gt; character into the output, specify two consecutive &lt;code&gt;%&lt;/code&gt; characters in the format string.  The first introduces a conversion specifier (as usual), and the second specifies that the conversion type is &lt;code&gt;%&lt;/code&gt;, which results in a single &lt;code&gt;&#39;%&#39;&lt;/code&gt; character in the output.&lt;/p&gt;
&lt;p&gt;In this example, &lt;code&gt;%d%%&lt;/code&gt; means a decimal integer conversion type followed by a literal &lt;code&gt;&#39;%&#39;&lt;/code&gt; character:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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;s1&quot;&gt;&amp;#39;Get &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%d%%&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt; off on &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%s&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt; today only!&amp;#39;&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;30&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;bananas&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;&amp;#39;Get 30% off on bananas today only!&amp;#39;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Note that the &lt;code&gt;%&lt;/code&gt; conversion type doesn&amp;rsquo;t consume any of the &lt;code&gt;&amp;lt;values&amp;gt;&lt;/code&gt; to the right of the string modulo operator.&lt;/p&gt;
&lt;h3 id=&quot;width-and-precision-specifiers&quot;&gt;Width and Precision Specifiers&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;&amp;lt;width&amp;gt;&lt;/code&gt; and &lt;code&gt;.&amp;lt;precision&amp;gt;&lt;/code&gt; sit in the middle of the conversion specifier:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;%[&amp;lt;flags&amp;gt;]&lt;/code&gt;&lt;strong&gt;&lt;code&gt;[&amp;lt;width&amp;gt;][.&amp;lt;precision&amp;gt;]&lt;/code&gt;&lt;/strong&gt;&lt;code&gt;&amp;lt;type&amp;gt;&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;They determine how much horizontal space a formatted value occupies.&lt;/p&gt;
&lt;h4 id=&quot;the-ltwidthgt-specifier&quot;&gt;The &lt;code&gt;&amp;lt;width&amp;gt;&lt;/code&gt; Specifier&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;&amp;lt;width&amp;gt;&lt;/code&gt; specifies the minimum width of the output field.  If the output is shorter than &lt;code&gt;&amp;lt;width&amp;gt;&lt;/code&gt;, then by default it is right-justified in a field that is &lt;code&gt;&amp;lt;width&amp;gt;&lt;/code&gt; characters wide, and padded with ASCII space characters on the left:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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;s1&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%5s&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;foo&amp;#39;&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;&amp;#39;  foo&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;s1&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%3d&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;&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;go&quot;&gt;&amp;#39;  4&amp;#39;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;(The justification and padding character can be modified. See &lt;strong&gt;conversion flags&lt;/strong&gt; below.)&lt;/p&gt;
&lt;p&gt;If the output length is greater than &lt;code&gt;&amp;lt;width&amp;gt;&lt;/code&gt;, then &lt;code&gt;&amp;lt;width&amp;gt;&lt;/code&gt; has no effect:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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;s1&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%2d&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1234&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;%d&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1234&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;(&amp;#39;1234&amp;#39;, &amp;#39;1234&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;s1&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%2s&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;foobar&amp;#39;&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;%s&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;foobar&amp;#39;&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;(&amp;#39;foobar&amp;#39;, &amp;#39;foobar&amp;#39;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Each of these examples specifies a field width of &lt;code&gt;2&lt;/code&gt;.  But since the values to be formatted are more than two characters, the result is the same as when no &lt;code&gt;&amp;lt;width&amp;gt;&lt;/code&gt; is specified.&lt;/p&gt;
&lt;h4 id=&quot;the-ltprecisiongt-specifier&quot;&gt;The &lt;code&gt;.&amp;lt;precision&amp;gt;&lt;/code&gt; Specifier&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;.&amp;lt;precision&amp;gt;&lt;/code&gt; affects the floating point, exponential, and string conversion types.&lt;/p&gt;
&lt;p&gt;For the &lt;code&gt;f&lt;/code&gt;, &lt;code&gt;F&lt;/code&gt;, &lt;code&gt;e&lt;/code&gt;, and &lt;code&gt;E&lt;/code&gt; types, &lt;code&gt;.&amp;lt;precision&amp;gt;&lt;/code&gt; determines the number of digits after the decimal point:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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;s1&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%.2f&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;123.456789&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;&amp;#39;123.46&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;s1&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%.2e&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;123.456789&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;&amp;#39;1.23e+02&amp;#39;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;For the &lt;code&gt;g&lt;/code&gt; and &lt;code&gt;G&lt;/code&gt; types, &lt;code&gt;.&amp;lt;precision&amp;gt;&lt;/code&gt; determines the total number of significant digits before and after the decimal point:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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;s1&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%.2g&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;123.456789&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;&amp;#39;1.2e+02&amp;#39;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;String values formatted with the &lt;code&gt;s&lt;/code&gt;, &lt;code&gt;r&lt;/code&gt;, and &lt;code&gt;a&lt;/code&gt; types are truncated to the length specified by &lt;code&gt;.&amp;lt;precision&amp;gt;&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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;s1&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%.4s&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;foobar&amp;#39;&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;&amp;#39;foob&amp;#39;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;It is very common to see &lt;code&gt;&amp;lt;width&amp;gt;&lt;/code&gt; and &lt;code&gt;.&amp;lt;precision&amp;gt;&lt;/code&gt; used together:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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;s1&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%8.2f&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;123.45678&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;&amp;#39;  123.46&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;s1&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%8.3s&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;foobar&amp;#39;&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;&amp;#39;     foo&amp;#39;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Either of &lt;code&gt;&amp;lt;width&amp;gt;&lt;/code&gt; or &lt;code&gt;.&amp;lt;precision&amp;gt;&lt;/code&gt; can be specified as an asterisk character (&lt;code&gt;*&lt;/code&gt;), in which case the value to be used is taken from the next item in the &lt;code&gt;&amp;lt;values&amp;gt;&lt;/code&gt; tuple:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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;s1&quot;&gt;&amp;#39;&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;o&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;123&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;&amp;#39;  123&amp;#39;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;There isn&amp;rsquo;t much need for this when the &lt;code&gt;&amp;lt;width&amp;gt;&lt;/code&gt; value is given as a constant.  There isn&amp;rsquo;t any functional difference between the example given above and this:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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;s1&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%5d&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;123&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;&amp;#39;  123&amp;#39;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;But you can also specify &lt;code&gt;&amp;lt;width&amp;gt;&lt;/code&gt; and &lt;code&gt;.&amp;lt;precision&amp;gt;&lt;/code&gt; by variable:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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;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;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;n&quot;&gt;w&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;Enter width: &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;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;[&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%*s&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;]&amp;#39;&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;w&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;foo&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;go&quot;&gt;Enter width: 2&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;[foo]&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Enter width: 4&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;[ foo]&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Enter width: 8&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;[     foo]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This allows the width or precision to be determined at run-time, and potentially change from one execution to the next.&lt;/p&gt;
&lt;h3 id=&quot;conversion-flags&quot;&gt;Conversion Flags&lt;/h3&gt;
&lt;p&gt;Optional conversion &lt;code&gt;&amp;lt;flags&amp;gt;&lt;/code&gt; are specified just after the initial &lt;code&gt;%&lt;/code&gt; character:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;%&lt;/code&gt;&lt;strong&gt;&lt;code&gt;[&amp;lt;flags&amp;gt;]&lt;/code&gt;&lt;/strong&gt;&lt;code&gt;[&amp;lt;width&amp;gt;][.&amp;lt;precision&amp;gt;]&amp;lt;type&amp;gt;&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;These allow finer control over the display of certain conversion types.  &lt;code&gt;&amp;lt;flags&amp;gt;&lt;/code&gt; can include any of the characters shown in the following table:&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;Character&lt;/th&gt;
&lt;th&gt;Controls&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;#&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Display of base or decimal point for integer and floating point values&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;0&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Padding of values that are shorter than the specified field width&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;-&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Justification of values that are shorter than the specified field width&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;+&lt;/code&gt;&lt;br&gt;&lt;code&gt;&#39; &#39;&lt;/code&gt; (space)&lt;/td&gt;
&lt;td&gt;Display of leading sign for numeric values&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;p&gt;The following sections explain how conversion flags operate in greater detail.&lt;/p&gt;
&lt;h4 id=&quot;the-flag&quot;&gt;The &lt;code&gt;#&lt;/code&gt; Flag&lt;/h4&gt;
&lt;p&gt;For the octal and hexadecimal conversion types, the &lt;code&gt;#&lt;/code&gt; flag causes base information to be included in the formatted output.  For the &lt;code&gt;o&lt;/code&gt; conversion type, this flag adds a leading &lt;code&gt;&#39;0o&#39;&lt;/code&gt;.  For the &lt;code&gt;x&lt;/code&gt; and &lt;code&gt;X&lt;/code&gt; conversion types, it adds a leading &lt;code&gt;&#39;0x&#39;&lt;/code&gt; or &lt;code&gt;&#39;0X&#39;&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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;s1&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%#o&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;16&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;&amp;#39;0o20&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;s1&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%#x&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;16&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;%#X&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;16&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;(&amp;#39;0x10&amp;#39;, &amp;#39;0X10&amp;#39;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;#&lt;/code&gt; flag is ignored for the decimal conversion types &lt;code&gt;d&lt;/code&gt;, &lt;code&gt;i&lt;/code&gt;, and &lt;code&gt;u&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;For floating point values, the &lt;code&gt;#&lt;/code&gt; flag forces the output to always contain a decimal point.  Ordinarily, floating point values will not contain a decimal point if there aren&amp;rsquo;t any digits after it.  This flag forces a decimal point to be included:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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;s1&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%.0f&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;123&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;&amp;#39;123&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;s1&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%#.0f&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;123&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;&amp;#39;123.&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;s1&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%.0e&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;123&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;&amp;#39;1e+02&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;s1&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%#.0e&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;123&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;&amp;#39;1.e+02&amp;#39;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This also works for values displayed in exponential notation, as shown.&lt;/p&gt;
&lt;h4 id=&quot;the-0-flag&quot;&gt;The &lt;code&gt;0&lt;/code&gt; Flag&lt;/h4&gt;
&lt;p&gt;When a formatted numeric value is shorter than the specified field width, the default behavior is to pad the field with ASCII space characters.  The &lt;code&gt;0&lt;/code&gt; flag causes padding with &lt;code&gt;&#39;0&#39;&lt;/code&gt; characters instead:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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;s1&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%05d&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;123&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;&amp;#39;00123&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;s1&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%08.2f&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;1.2&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;&amp;#39;00001.20&amp;#39;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;0&lt;/code&gt; flag can be used with all the numeric conversion types:  &lt;code&gt;d&lt;/code&gt;, &lt;code&gt;i&lt;/code&gt;, &lt;code&gt;u&lt;/code&gt;, &lt;code&gt;x&lt;/code&gt;, &lt;code&gt;X&lt;/code&gt;, &lt;code&gt;o&lt;/code&gt;, &lt;code&gt;f&lt;/code&gt;, &lt;code&gt;F&lt;/code&gt;, &lt;code&gt;e&lt;/code&gt;, &lt;code&gt;E&lt;/code&gt;, &lt;code&gt;g&lt;/code&gt;, and &lt;code&gt;G&lt;/code&gt;.&lt;/p&gt;
&lt;h4 id=&quot;the-flag_1&quot;&gt;The &lt;code&gt;-&lt;/code&gt; Flag&lt;/h4&gt;
&lt;p&gt;When a formatted value is shorter than the specified field width, it is usually right-justified in the field.  The &lt;code&gt;-&lt;/code&gt; flag causes the value to be left-justified in the specified field instead:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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;s1&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%-5d&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;123&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;&amp;#39;123  &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;s1&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%-8.2f&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;123.3&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;&amp;#39;123.30  &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;s1&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%-*s&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;&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;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;foo&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;&amp;#39;foo       &amp;#39;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You can use the &lt;code&gt;-&lt;/code&gt; flag with the string conversion types &lt;code&gt;s&lt;/code&gt;, &lt;code&gt;a&lt;/code&gt;, and &lt;code&gt;r&lt;/code&gt;, as well as all the numeric conversion types.  For numeric types, if both &lt;code&gt;0&lt;/code&gt; and &lt;code&gt;-&lt;/code&gt; are present, then &lt;code&gt;0&lt;/code&gt; is ignored.&lt;/p&gt;
&lt;h4 id=&quot;the-and-flags&quot;&gt;The &lt;code&gt;+&lt;/code&gt; and &lt;code&gt;&#39; &#39;&lt;/code&gt; Flags&lt;/h4&gt;
&lt;p&gt;By default, positive numeric values do not have a leading sign character.  The &lt;code&gt;+&lt;/code&gt; flag adds a &lt;code&gt;&#39;+&#39;&lt;/code&gt; character to the left of numeric output:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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;s1&quot;&gt;&amp;#39;&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;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;&amp;#39;+3&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;s1&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%+5d&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;&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;go&quot;&gt;&amp;#39;   +3&amp;#39;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;&#39; &#39;&lt;/code&gt; (space character) flag causes positive numeric values to be preceded by a space character:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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;s1&quot;&gt;&amp;#39;&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;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;&amp;#39; 3&amp;#39;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;These flags have no effect on negative numeric values, which always have a leading &lt;code&gt;&#39;-&#39;&lt;/code&gt; character.&lt;/p&gt;
&lt;h3 id=&quot;specifying-values-by-dictionary-mapping&quot;&gt;Specifying Values by Dictionary Mapping&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;&amp;lt;values&amp;gt;&lt;/code&gt; inserted into the format string may be specified as a dictionary instead of a tuple.  In that case, each conversion specifier must contain one of the dictionary keys in parentheses immediately following the &lt;code&gt;&#39;%&#39;&lt;/code&gt; character.  &lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s an example:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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;s1&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%d&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%s&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt; cost $&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%.2f&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;&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;6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;bananas&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;1.74&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;&amp;#39;6 bananas cost $1.74&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;d&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;quantity&amp;#39;&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;s1&quot;&gt;&amp;#39;item&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;bananas&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;price&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;1.74&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;hll&quot;&gt;&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%(quantity)d&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%(item)s&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt; cost $&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%(price).2f&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;d&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;go&quot;&gt;&amp;#39;6 bananas cost $1.74&amp;#39;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Using this technique, you can specify the inserted values in any order:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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;d&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;quantity&amp;#39;&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;s1&quot;&gt;&amp;#39;item&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;bananas&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;price&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;1.74&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;s1&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%(quantity)d&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%(item)s&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt; cost $&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%(price).2f&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;d&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;&amp;#39;6 bananas cost $1.74&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;s1&quot;&gt;&amp;#39;It will cost you $&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%(price).2f&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt; for &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%(item)s&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;, if you buy &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%(quantity)d&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;d&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;&amp;#39;It will cost you $1.74 for bananas, if you buy 6&amp;#39;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;All the conversion specifier items shown above&amp;mdash;&lt;code&gt;&amp;lt;flags&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;width&amp;gt;&lt;/code&gt;, &lt;code&gt;.&amp;lt;precision&amp;gt;&lt;/code&gt;, and &lt;code&gt;&amp;lt;type&amp;gt;&lt;/code&gt;&amp;mdash;still have the same meaning:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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;s1&quot;&gt;&amp;#39;Quantity: &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%(quantity)03d&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;d&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;&amp;#39;Quantity: 006&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;s1&quot;&gt;&amp;#39;Item:     &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%(item).5s&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;d&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;&amp;#39;Item:     banan&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;Note:&lt;/strong&gt; If you specify &lt;code&gt;&amp;lt;values&amp;gt;&lt;/code&gt; by dictionary mapping, then you can&amp;rsquo;t use &lt;code&gt;*&lt;/code&gt; to specify &lt;code&gt;&amp;lt;width&amp;gt;&lt;/code&gt; or &lt;code&gt;.&amp;lt;precision&amp;gt;&lt;/code&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;h2 id=&quot;python-input-and-output-conclusion&quot;&gt;Python Input and Output: Conclusion&lt;/h2&gt;
&lt;p&gt;In this tutorial, you learned about Python input and output, and how your Python program can communicate with the user.  You should now be able to obtain data from the user with &lt;strong&gt;&lt;code&gt;input()&lt;/code&gt;&lt;/strong&gt;, and display results to the console with &lt;strong&gt;&lt;code&gt;print()&lt;/code&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;You also learned how to make data displayed to the user more presentable by formatting it with the &lt;strong&gt;string modulo operator&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;As versatile as the string modulo operator is, Python provides two newer ways to format string data that are even better:  the &lt;strong&gt;string &lt;code&gt;.format()&lt;/code&gt; method&lt;/strong&gt; and the &lt;strong&gt;formatted string literal&lt;/strong&gt;.  Head to the next tutorial to learn about them!&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/python-for-loop/&quot;&gt; «&amp;nbsp;Definite Iteration in Python&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;Basic Input and Output in Python&lt;/a&gt;&lt;/div&gt;
    &lt;div class=&quot;col-12 col-md-3 text-right text-muted mr-1&quot;&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>How to Use Python lambda Functions</title>
      <id>https://realpython.com/python-lambda/</id>
      <link href="https://realpython.com/python-lambda/"/>
      <updated>2019-06-19T14:00:00+00:00</updated>
      <summary>In this step-by-step tutorial, you&#39;ll learn about Python lambda functions. You&#39;ll see how they compare with regular functions and how you can use them in accordance with best practices.</summary>
      <content type="html">
        &lt;p&gt;Python and other languages like Java, C#, and even C++ have had lambda functions added to their syntax, whereas languages like LISP or the ML family of languages, Haskell, OCaml, and F#, use lambdas as a core concept.&lt;/p&gt;
&lt;p&gt;Python lambdas are little, anonymous functions, subject to a more restrictive but more concise syntax than regular Python functions.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;By the end of this article, you&amp;rsquo;ll know:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;How Python lambdas came to be &lt;/li&gt;
&lt;li&gt;How lambdas compare with regular function objects&lt;/li&gt;
&lt;li&gt;How to write lambda functions&lt;/li&gt;
&lt;li&gt;Which functions in the Python standard library leverage lambdas&lt;/li&gt;
&lt;li&gt;When to use or avoid Python lambda functions&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;Notes&lt;/strong&gt;: You&amp;rsquo;ll see some code examples using &lt;code&gt;lambda&lt;/code&gt; that seem to blatantly ignore Python style best practices. This is only intended to illustrate lambda calculus concepts or to highlight the capabilities of Python &lt;code&gt;lambda&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Those questionable examples will be contrasted with better approaches or alternatives as you progress through the article.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;This tutorial is mainly for intermediate to experienced Python programmers, but it is accessible to any curious minds with interest in programming and lambda calculus.&lt;/p&gt;
&lt;p&gt;All the examples included in this tutorial have been tested with Python 3.7.&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;lambda-calculus&quot;&gt;Lambda Calculus&lt;/h2&gt;
&lt;p&gt;Lambda expressions in Python and other programming languages have their roots in lambda calculus, a model of computation invented by Alonzo Church. You&amp;rsquo;ll uncover when lambda calculus was introduced and why it&amp;rsquo;s a fundamental concept that ended up in the Python ecosystem.&lt;/p&gt;
&lt;h3 id=&quot;history&quot;&gt;History&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Alonzo_Church&quot;&gt;Alonzo Church&lt;/a&gt; formalized &lt;a href=&quot;https://en.wikipedia.org/wiki/Lambda_calculus&quot;&gt;lambda calculus&lt;/a&gt;, a language based on pure abstraction, in the 1930s. Lambda functions are also referred to as lambda abstractions, a direct reference to the abstraction model of Alonzo Church&amp;rsquo;s original creation.&lt;/p&gt;
&lt;p&gt;Lambda calculus can encode any computation. It is &lt;a href=&quot;https://simple.wikipedia.org/wiki/Turing_complete&quot;&gt;Turing complete&lt;/a&gt;, but contrary to the concept of a &lt;a href=&quot;https://en.wikipedia.org/wiki/Turing_machine&quot;&gt;Turing machine&lt;/a&gt;, it is pure and does not keep any state.&lt;/p&gt;
&lt;p&gt;Functional languages get their origin in mathematical logic and lambda calculus, while imperative programming languages embrace the state-based model of computation invented by Alan Turing. The two models of computation, lambda calculus and &lt;a href=&quot;https://en.wikipedia.org/wiki/Turing_machine&quot;&gt;Turing machines&lt;/a&gt;, can be translated into each another. This equivalence is known as the &lt;a href=&quot;https://en.wikipedia.org/wiki/Church%E2%80%93Turing_thesis&quot;&gt;Church-Turing hypothesis&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Functional languages directly inherit the lambda calculus philosophy, adopting a declarative approach of programming that emphasizes abstraction, data transformation, composition, and purity (no state and no side effects). Examples of functional languages include &lt;a href=&quot;https://www.haskell.org/&quot;&gt;Haskell&lt;/a&gt;, &lt;a href=&quot;https://en.wikipedia.org/wiki/Lisp_%28programming_language%29&quot;&gt;Lisp&lt;/a&gt;, or &lt;a href=&quot;https://www.erlang.org/&quot;&gt;Erlang&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;By contrast, the Turing Machine led to imperative programming found in languages like &lt;a href=&quot;https://en.wikipedia.org/wiki/Fortran&quot;&gt;Fortran&lt;/a&gt;, &lt;a href=&quot;https://en.wikipedia.org/wiki/C_%28programming_language%29&quot;&gt;C&lt;/a&gt;, or &lt;a href=&quot;https://www.python.org/&quot;&gt;Python&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The imperative style consists of programming with statements, driving the flow of the program step by step with detailed instructions. This approach promotes mutation and requires managing state.&lt;/p&gt;
&lt;p&gt;The separation in both families presents some nuances, as some functional languages incorporate imperative features, like &lt;a href=&quot;http://www.ocaml.org/&quot;&gt;OCaml&lt;/a&gt;, while functional features have been permeating the imperative family of languages in particular with the introduction of lambda functions in &lt;a href=&quot;https://en.wikipedia.org/wiki/Java_%28programming_language%29&quot;&gt;Java&lt;/a&gt;, or Python.&lt;/p&gt;
&lt;p&gt;Python is not inherently a functional language, but it adopted some functional concepts early on. In January 1994, &lt;code&gt;map()&lt;/code&gt;, &lt;code&gt;filter()&lt;/code&gt;, &lt;code&gt;reduce()&lt;/code&gt;, and the &lt;code&gt;lambda&lt;/code&gt; operator were added to the language.&lt;/p&gt;
&lt;h3 id=&quot;first-example&quot;&gt;First Example&lt;/h3&gt;
&lt;p&gt;Here are a few examples to give you an appetite for some Python code, functional style.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;https://en.wikipedia.org/wiki/Identity_function&quot;&gt;identity function&lt;/a&gt;, a function that returns its argument, is expressed with a standard Python function definition using the keyword &lt;code&gt;def&lt;/code&gt; as follows:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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;identity&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;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;code&gt;identity()&lt;/code&gt; takes an argument &lt;code&gt;x&lt;/code&gt; and returns it upon invocation.&lt;/p&gt;
&lt;p&gt;In contrast, if you use a Python lambda construction, you get the following:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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;lambda&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;/pre&gt;&lt;/div&gt;

&lt;p&gt;In the example above, the expression is composed of:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;The keyword:&lt;/strong&gt; &lt;code&gt;lambda&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A bound variable:&lt;/strong&gt; &lt;code&gt;x&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A body:&lt;/strong&gt; &lt;code&gt;x&lt;/code&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;: In the context of this article, a &lt;strong&gt;bound variable&lt;/strong&gt; is an argument to a lambda function. &lt;/p&gt;
&lt;p&gt;In contrast, a &lt;strong&gt;free variable&lt;/strong&gt; is not bound and may be referenced in the body of the expression. A free variable can be a constant or a variable defined in the enclosing scope of the function.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;You can write a slightly more elaborated example, a function that adds &lt;code&gt;1&lt;/code&gt; to an argument, as follows:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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;lambda&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;mi&quot;&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You can apply the function above to an argument by surrounding the function and its argument with parentheses:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;lambda&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;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;go&quot;&gt;3&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Reduction_strategy_%28lambda_calculus%29&quot;&gt;Reduction&lt;/a&gt; is a lambda calculus strategy to compute the value of the expression. It consists of substituting the argument &lt;code&gt;2&lt;/code&gt; for &lt;code&gt;x&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight text&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;(lambda x: x + 1)(2) = lambda 2: 2 + 1
                     = 2 + 1
                     = 3
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Because a lambda function is an expression, it can be named. Therefore you could write the previous code as follows:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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;add_one&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;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;mi&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;add_one&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;3&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The above lambda function is equivalent to writing 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;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;add_one&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;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;mi&quot;&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;These functions all take a single argument. You may have noticed that, in the definition of the lambdas, the arguments don&amp;rsquo;t have parentheses around them. Multi-argument functions  (functions that take more than one argument) are expressed in Python lambdas by listing arguments and separating them with a comma (&lt;code&gt;,&lt;/code&gt;) but without surrounding them with parentheses:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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;full_name&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;first&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;last&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;Full name: {first.title()} {last.title()}&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;full_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;guido&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;van rossum&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;&amp;#39;Full name: Guido Van Rossum&amp;#39;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The lambda function assigned to &lt;code&gt;full_name&lt;/code&gt; takes two arguments and returns a string interpolating the two parameters &lt;code&gt;first&lt;/code&gt; and &lt;code&gt;last&lt;/code&gt;. As expected, the definition of the lambda lists the arguments with no parentheses, whereas calling the function is done exactly like a normal Python function, with parentheses surrounding the arguments.&lt;/p&gt;
&lt;h2 id=&quot;anonymous-functions&quot;&gt;Anonymous Functions&lt;/h2&gt;
&lt;p&gt;The following terms may be used interchangeably depending on the programming language type and culture:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Anonymous functions&lt;/li&gt;
&lt;li&gt;Lambda functions&lt;/li&gt;
&lt;li&gt;Lambda expressions&lt;/li&gt;
&lt;li&gt;Lambda abstractions&lt;/li&gt;
&lt;li&gt;Lambda form&lt;/li&gt;
&lt;li&gt;Function literals&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For the rest of this article after this section, you&amp;rsquo;ll mostly see the term &lt;strong&gt;lambda function&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Taken literally, an anonymous function is a function without a name. In Python, an anonymous function is created with the &lt;code&gt;lambda&lt;/code&gt; keyword. More loosely, it may or not be assigned a name. Consider a two-argument anonymous function defined with &lt;code&gt;lambda&lt;/code&gt; but not bound to a variable. The lambda is not given a name:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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;lambda&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;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The function above defines a lambda expression that takes two arguments and returns their sum.&lt;/p&gt;
&lt;p&gt;Other than providing you with the feedback that Python is perfectly fine with this form, it doesn&amp;rsquo;t lead to any practical use. You could invoke the function in the Python interpreter:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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;_&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;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;3&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The example above is taking advantage of the interactive interpreter-only feature provided via the underscore (&lt;code&gt;_&lt;/code&gt;). See the note below for more details. &lt;/p&gt;
&lt;p&gt;You could not write similar code in a Python module. Consider the &lt;code&gt;_&lt;/code&gt; in the interpreter as a side effect that you took advantage of. In a Python module, you would assign a name to the lambda, or you would pass the lambda to a function. You&amp;rsquo;ll use those two approaches 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;Note&lt;/strong&gt;: In the interactive interpreter, the single underscore (&lt;code&gt;_&lt;/code&gt;) is bound to the last expression evaluated. &lt;/p&gt;
&lt;p&gt;In the example above, the &lt;code&gt;_&lt;/code&gt; points to the lambda function. For more details about the usage of this special character in Python, check out &lt;a href=&quot;https://dbader.org/blog/meaning-of-underscores-in-python&quot;&gt;The Meaning of Underscores in Python&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;Another pattern used in other languages like JavaScript is to immediately execute a Python lambda function. This is known as an &lt;strong&gt;Immediately Invoked Function Expression&lt;/strong&gt; (&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Glossary/IIFE&quot;&gt;IIFE&lt;/a&gt;, pronounce &amp;ldquo;iffy&amp;rdquo;). Here&amp;rsquo;s an example:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;lambda&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;x&lt;/span&gt; &lt;span class=&quot;o&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;mi&quot;&gt;2&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;go&quot;&gt;5&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The lambda function above is defined and then immediately called with two arguments (&lt;code&gt;2&lt;/code&gt; and &lt;code&gt;3&lt;/code&gt;). It returns the value &lt;code&gt;5&lt;/code&gt;, which is the sum of the arguments.&lt;/p&gt;
&lt;p&gt;Several examples in this tutorial use this format to highlight the anonymous aspect of a lambda function and avoid focusing on &lt;code&gt;lambda&lt;/code&gt; in Python as a shorter way of defining a function.&lt;/p&gt;
&lt;p&gt;Python does not encourage using immediately invoked lambda expressions. It simply results from a lambda expression being callable, unlike the body of a normal function.&lt;/p&gt;
&lt;p&gt;Lambda functions are frequently used with &lt;a href=&quot;https://en.wikipedia.org/wiki/Higher-order_function&quot;&gt;higher-order functions&lt;/a&gt;, which take one or more functions as arguments or return one or more functions.&lt;/p&gt;
&lt;p&gt;A lambda function can be a higher-order function by taking a function (normal or lambda) as an argument like in the following contrived example:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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;high_ord_func&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;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;func&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;func&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;n&quot;&gt;high_ord_func&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;lambda&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;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;6&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;high_ord_func&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;lambda&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;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;7&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Python exposes higher-order functions as built-in functions or in the standard library. Examples include &lt;code&gt;map()&lt;/code&gt;, &lt;code&gt;filter()&lt;/code&gt;, &lt;code&gt;functools.reduce()&lt;/code&gt;, as well as key functions like &lt;code&gt;sort()&lt;/code&gt;,  &lt;code&gt;sorted()&lt;/code&gt;, &lt;code&gt;min()&lt;/code&gt;, and &lt;code&gt;max()&lt;/code&gt;. You&amp;rsquo;ll use lambda functions together with Python higher-order functions in &lt;a href=&quot;#appropriate-uses-of-lambda-expressions&quot;&gt;Appropriate Uses of Lambda Expressions&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;python-lambda-and-regular-functions&quot;&gt;Python Lambda and Regular Functions&lt;/h2&gt;
&lt;p&gt;This quote from the &lt;a href=&quot;https://docs.python.org/3/faq/design.html&quot;&gt;Python Design and History FAQ&lt;/a&gt; seems to set the tone about the overall expectation regarding the usage of lambda functions in Python:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Unlike lambda forms in other languages, where they add functionality, Python lambdas are only a shorthand notation if you&amp;rsquo;re too lazy to define a function. (&lt;a href=&quot;https://docs.python.org/3/faq/design.html#why-can-t-lambda-expressions-contain-statements&quot;&gt;Source&lt;/a&gt;)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Nevertheless, don&amp;rsquo;t let this statement deter you from using Python&amp;rsquo;s &lt;code&gt;lambda&lt;/code&gt;. At first glance, you may accept that a lambda function is a function with some &lt;a href=&quot;https://en.wikipedia.org/wiki/Syntactic_sugar&quot;&gt;syntactic sugar&lt;/a&gt; shortening the code to define or invoke a function. The following sections highlight the commonalities and subtle differences between normal Python functions and lambda functions.&lt;/p&gt;
&lt;h3 id=&quot;functions&quot;&gt;Functions&lt;/h3&gt;
&lt;p&gt;At this point, you may wonder what fundamentally distinguishes a lambda function bound to a variable from a regular function with a single &lt;code&gt;return&lt;/code&gt; line: under the surface, almost nothing. Let&amp;rsquo;s verify how Python sees a function built with a single return statement versus a function constructed as an expression (&lt;code&gt;lambda&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;https://docs.python.org/3/library/dis.html&quot;&gt;&lt;code&gt;dis&lt;/code&gt;&lt;/a&gt; module exposes functions to analyze Python bytecode generated by the Python compiler:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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;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;add&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;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;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&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;type&lt;/span&gt;&lt;span class=&quot;p&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;go&quot;&gt;&amp;lt;class &amp;#39;function&amp;#39;&amp;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;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;add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  1           0 LOAD_FAST                0 (x)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;              2 LOAD_FAST                1 (y)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;              4 BINARY_ADD&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;              6 RETURN_VALUE&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;add&lt;/span&gt;
&lt;span class=&quot;hll&quot;&gt;&lt;span class=&quot;go&quot;&gt;&amp;lt;function &amp;lt;lambda&amp;gt; at 0x7f30c6ce9ea0&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You can see that &lt;code&gt;dis()&lt;/code&gt; expose a readable version of the Python bytecode allowing the inspection of the low-level instructions that the Python interpreter will use while executing the program.&lt;/p&gt;
&lt;p&gt;Now see it with a regular function object:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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;dis&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;add&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;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;y&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;type&lt;/span&gt;&lt;span class=&quot;p&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;go&quot;&gt;&amp;lt;class &amp;#39;function&amp;#39;&amp;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;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;add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  1           0 LOAD_FAST                0 (x)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;              2 LOAD_FAST                1 (y)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;              4 BINARY_ADD&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;              6 RETURN_VALUE&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;add&lt;/span&gt;
&lt;span class=&quot;hll&quot;&gt;&lt;span class=&quot;go&quot;&gt;&amp;lt;function add at 0x7f30c6ce9f28&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The bytecode interpreted by Python is the same for both functions. But you may notice that the naming is different: the function name is &lt;code&gt;add&lt;/code&gt; for a function defined with &lt;code&gt;def&lt;/code&gt;, whereas the Python lambda function is seen as &lt;code&gt;lambda&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;traceback&quot;&gt;Traceback&lt;/h3&gt;
&lt;p&gt;You saw in the previous section that, in the context of the lambda function, Python did not provide the name of the function, but only &lt;code&gt;&amp;lt;lambda&amp;gt;&lt;/code&gt;. This can be a limitation to consider when an exception occurs, and a traceback shows only &lt;code&gt;&amp;lt;lambda&amp;gt;&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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;div_zero&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;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;mi&quot;&gt;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;div_zero&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;gt&quot;&gt;Traceback (most recent call last):&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;File&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;&amp;lt;stdin&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;line&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;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;module&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;hll&quot;&gt;    &lt;span class=&quot;n&quot;&gt;File&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;&amp;lt;stdin&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;line&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;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;lambda&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;gr&quot;&gt;ZeroDivisionError&lt;/span&gt;: &lt;span class=&quot;n&quot;&gt;division by zero&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The traceback of an exception raised while a lambda function is executed only identifies the function causing the exception as &lt;code&gt;&amp;lt;lambda&amp;gt;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s the same exception raised by a normal function:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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;div_zero&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;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;mi&quot;&gt;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;div_zero&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;gt&quot;&gt;Traceback (most recent call last):&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;File&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;&amp;lt;stdin&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;line&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;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;module&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;hll&quot;&gt;    &lt;span class=&quot;n&quot;&gt;File&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;&amp;lt;stdin&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;line&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;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;div_zero&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;gr&quot;&gt;ZeroDivisionError&lt;/span&gt;: &lt;span class=&quot;n&quot;&gt;division by zero&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The normal function causes a similar error but results in a more precise traceback because it gives the function name, &lt;code&gt;div_zero&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;syntax&quot;&gt;Syntax&lt;/h3&gt;
&lt;p&gt;As you saw in the previous sections, a lambda form presents syntactic distinctions from a normal function. In particular, a lambda function has the following characteristics:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It can only contain expressions and can&amp;rsquo;t include statements in its body.&lt;/li&gt;
&lt;li&gt;It is written as a single line of execution.&lt;/li&gt;
&lt;li&gt;It does not support type annotations.&lt;/li&gt;
&lt;li&gt;It can be immediately invoked (IIFE).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;No Statements&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;A lambda function can&amp;rsquo;t contain any statements. In a lambda function, statements like &lt;code&gt;return&lt;/code&gt;,  &lt;code&gt;pass&lt;/code&gt;, &lt;code&gt;assert&lt;/code&gt;, or &lt;code&gt;raise&lt;/code&gt; will raise a &lt;code&gt;SyntaxError&lt;/code&gt; exception. Here&amp;rsquo;s an example of adding &lt;code&gt;assert&lt;/code&gt; to the body of a lambda:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;lambda&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;assert&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;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  File &lt;span class=&quot;nb&quot;&gt;&amp;quot;&amp;lt;input&amp;gt;&amp;quot;&lt;/span&gt;, line &lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;lambda&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;assert&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;mi&quot;&gt;2&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;gr&quot;&gt;SyntaxError&lt;/span&gt;: &lt;span class=&quot;n&quot;&gt;invalid syntax&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This contrived example intended to &lt;code&gt;assert&lt;/code&gt; that parameter &lt;code&gt;x&lt;/code&gt; had a value of &lt;code&gt;2&lt;/code&gt;. But, the interpreter identifies a &lt;code&gt;SyntaxError&lt;/code&gt; while parsing the code that involves the statement &lt;code&gt;assert&lt;/code&gt; in the body of the &lt;code&gt;lambda&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Single Expression&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;In contrast to a normal function, a Python lambda function is a single expression. Although, in the body of a &lt;code&gt;lambda&lt;/code&gt;, you can spread the expression over several lines using parentheses or a multiline string, it remains a single expression:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;lambda&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;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;ow&quot;&gt;and&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;odd&amp;#39;&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;even&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;go&quot;&gt;&amp;#39;odd&amp;#39;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The example above returns the string &lt;code&gt;&#39;odd&#39;&lt;/code&gt; when the lambda argument is odd, and &lt;code&gt;&#39;even&#39;&lt;/code&gt; when the argument is even. It spreads across two lines because it is contained in a set of parentheses, but it remains a single expression.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Type Annotations&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;ve started adopting type hinting, which is now available in Python, then you have another good reason to prefer normal functions over Python lambda functions. Check out &lt;a href=&quot;https://realpython.com/python-type-checking/#hello-types&quot;&gt;Python Type Checking (Guide)&lt;/a&gt; to get learn more about Python type hints and type checking. In a lambda function, there is no equivalent for 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;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;full_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;first&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;last&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;str&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;f&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;{first.title()} {last.title()}&amp;#39;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Any type error with &lt;code&gt;full_name()&lt;/code&gt; can be caught by tools like &lt;a href=&quot;http://mypy-lang.org/&quot;&gt;&lt;code&gt;mypy&lt;/code&gt;&lt;/a&gt; or &lt;a href=&quot;https://pyre-check.org/&quot;&gt;&lt;code&gt;pyre&lt;/code&gt;&lt;/a&gt;, whereas a &lt;code&gt;SyntaxError&lt;/code&gt; with the equivalent lambda function is raised at runtime:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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;lambda&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;first&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;last&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;first&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;title&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;s2&quot;&gt;&amp;quot; &amp;quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;last&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;str&lt;/span&gt;
  File &lt;span class=&quot;nb&quot;&gt;&amp;quot;&amp;lt;stdin&amp;gt;&amp;quot;&lt;/span&gt;, line &lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;lambda&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;first&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;last&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;first&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;title&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;s2&quot;&gt;&amp;quot; &amp;quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;last&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;str&lt;/span&gt;

&lt;span class=&quot;go&quot;&gt;SyntaxError: invalid syntax&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Like trying to include a statement in a lambda, adding type annotation immediately results in a &lt;code&gt;SyntaxError&lt;/code&gt; at runtime.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;IIFE&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;You&amp;rsquo;ve already seen several examples of &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Glossary/IIFE&quot;&gt;immediately invoked function execution&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;lambda&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;x&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;go&quot;&gt;9&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Outside of the Python interpreter, this feature is probably not used in practice. It&amp;rsquo;s a direct consequence of a lambda function being callable as it is defined. For example, this allows you to pass the definition of a Python lambda expression to a higher-order function like &lt;code&gt;map()&lt;/code&gt;, &lt;code&gt;filter()&lt;/code&gt;, or  &lt;code&gt;functools.reduce()&lt;/code&gt;, or to a key function.&lt;/p&gt;
&lt;h3 id=&quot;arguments&quot;&gt;Arguments&lt;/h3&gt;
&lt;p&gt;Like a normal function object defined with &lt;code&gt;def&lt;/code&gt;, Python lambda expressions support all the different ways of passing arguments. This includes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Positional arguments&lt;/li&gt;
&lt;li&gt;Named arguments (sometimes called keyword arguments)&lt;/li&gt;
&lt;li&gt;Variable list of arguments (often referred to as &lt;strong&gt;varargs&lt;/strong&gt;)&lt;/li&gt;
&lt;li&gt;Variable list of keyword arguments&lt;/li&gt;
&lt;li&gt;Keyword-only arguments&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The following examples illustrate options open to you in order to pass arguments to lambda expressions:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;lambda&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;z&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;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;z&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;2&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;go&quot;&gt;6&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;k&quot;&gt;lambda&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;z&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;x&lt;/span&gt; &lt;span class=&quot;o&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;z&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;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;6&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;k&quot;&gt;lambda&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;z&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;x&lt;/span&gt; &lt;span class=&quot;o&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;z&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;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;6&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;k&quot;&gt;lambda&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;nb&quot;&gt;sum&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;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;2&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;go&quot;&gt;6&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;k&quot;&gt;lambda&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;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;kwargs&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;values&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()))(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;one&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;n&quot;&gt;two&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;three&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;go&quot;&gt;6&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;k&quot;&gt;lambda&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;o&quot;&gt;*&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;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;z&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;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&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;z&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;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;z&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;go&quot;&gt;6&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id=&quot;decorators&quot;&gt;Decorators&lt;/h3&gt;
&lt;p&gt;In Python, a &lt;a href=&quot;https://www.python.org/dev/peps/pep-0318/&quot;&gt;decorator&lt;/a&gt; is the implementation of a pattern that allows adding a behavior to a function or a class. It is usually expressed with the &lt;code&gt;@decorator&lt;/code&gt; syntax prefixing a function. Here&amp;rsquo;s a contrived 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;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;some_decorator&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;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;wraps&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;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;s2&quot;&gt;&amp;quot;Calling function &amp;#39;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{f.__name__}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;#39;&amp;quot;&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;f&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;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;wraps&lt;/span&gt;

&lt;span class=&quot;nd&quot;&gt;@some_decorator&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;decorated_function&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;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;s2&quot;&gt;&amp;quot;With argument &amp;#39;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{x}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;#39;&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In the example above, &lt;code&gt;some_decorator()&lt;/code&gt; is a function that adds a behavior to &lt;code&gt;decorated_function()&lt;/code&gt;, so that invoking &lt;code&gt;decorated_function(&quot;Python&quot;)&lt;/code&gt; results in 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;go&quot;&gt;Calling function &amp;#39;decorated_function&amp;#39;&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;With argument &amp;#39;Python&amp;#39;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;code&gt;decorated_function()&lt;/code&gt; only prints &lt;code&gt;With argument &#39;Python&#39;&lt;/code&gt;, but the decorator adds an extra behavior that also prints &lt;code&gt;Calling function &#39;decorated_function&#39;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;A decorator can be applied to a lambda. Although it&amp;rsquo;s not possible to decorate a lambda with the &lt;code&gt;@decorator&lt;/code&gt; syntax, a decorator is just a function, so it can call the lambda function:&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;c1&quot;&gt;# Defining a decorator&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;trace&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;lineno&quot;&gt; 3 &lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;wrap&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;span class=&quot;lineno&quot;&gt; 4 &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;s2&quot;&gt;&amp;quot;[TRACE] func: &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{f.__name__}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;, args: &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{args}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;, kwargs: &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{kwargs}&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; 5 &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;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;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;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;wrap&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 8 &lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 9 &lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;# Applying decorator to a function&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;10 &lt;/span&gt;&lt;span class=&quot;nd&quot;&gt;@trace&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;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;add_two&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&gt;&lt;span class=&quot;lineno&quot;&gt;12 &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;mi&quot;&gt;2&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;13 &lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;14 &lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;# Calling the decorated function&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;add_two&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&gt;&lt;span class=&quot;lineno&quot;&gt;16 &lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;17 &lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;# Applying decorator to a lambda&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;nb&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;trace&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;lambda&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;mi&quot;&gt;2&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&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;code&gt;add_two()&lt;/code&gt;, decorated with &lt;code&gt;@trace&lt;/code&gt; on line 11, is invoked with argument &lt;code&gt;3&lt;/code&gt; on line 15. By contrast, on line 18, a lambda function is immediately involved and embedded in a call to &lt;code&gt;trace()&lt;/code&gt;, the decorator. When you execute the code above you obtain 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;go&quot;&gt;[TRACE] func: add_two, args: (3,), kwargs: {}&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;[TRACE] func: &amp;lt;lambda&amp;gt;, args: (3,), kwargs: {}&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;9&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;See how, as you&amp;rsquo;ve already seen, the name of the lambda function appears as &lt;code&gt;&amp;lt;lambda&amp;gt;&lt;/code&gt;, whereas &lt;code&gt;add_two&lt;/code&gt; is clearly identified for the normal function.&lt;/p&gt;
&lt;p&gt;Decorating the lambda function this way could be useful for debugging purposes, possibly to debug the behavior of a lambda function used in the context of a higher-order function or a key function. Let&amp;rsquo;s see an example with &lt;code&gt;map()&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;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;trace&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;lambda&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;mi&quot;&gt;2&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 first argument of &lt;code&gt;map()&lt;/code&gt; is a lambda that multiplies its argument by &lt;code&gt;2&lt;/code&gt;. This lambda is decorated with &lt;code&gt;trace()&lt;/code&gt;. When executed, the example above outputs 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;go&quot;&gt;[TRACE] Calling &amp;lt;lambda&amp;gt; with args (0,) and kwargs {}&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;[TRACE] Calling &amp;lt;lambda&amp;gt; with args (1,) and kwargs {}&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;[TRACE] Calling &amp;lt;lambda&amp;gt; with args (2,) and kwargs {}&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;[0, 2, 4]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The result &lt;code&gt;[0, 2, 4]&lt;/code&gt; is a list obtained from multiplying each element of &lt;code&gt;range(3)&lt;/code&gt;. For now, consider &lt;code&gt;range(3)&lt;/code&gt; equivalent to the list &lt;code&gt;[0, 1, 2]&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;You will be exposed to &lt;code&gt;map()&lt;/code&gt; in more details in &lt;a href=&quot;#map&quot;&gt;Map&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;A lambda can also be a decorator, but it&amp;rsquo;s not recommended. If you find yourself needing to do this, consult &lt;a href=&quot;https://www.python.org/dev/peps/pep-0008/#programming-recommendations&quot;&gt;PEP 8, Programming Recommendations&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;For more on Python decorators, check out &lt;a href=&quot;https://realpython.com/primer-on-python-decorators/&quot;&gt;Primer on Python Decorators&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;closure&quot;&gt;Closure&lt;/h3&gt;
&lt;p&gt;A &lt;a href=&quot;https://en.wikipedia.org/wiki/Closure_%28computer_programming%29&quot;&gt;closure&lt;/a&gt; is a function where every free variable, everything except parameters, used in that function is bound to a specific value defined in the enclosing scope of that function. In effect, closures define the environment in which they run, and so can be called from anywhere.&lt;/p&gt;
&lt;p&gt;The concepts of lambdas and closures are not necessarily related, although lambda functions can be closures in the same way that normal functions can also be closures. Some languages have special constructs for closure or lambda (for example, Groovy with an anonymous block of code as Closure object), or a lambda expression (for example, Java Lambda expression with a limited option for closure).&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s a closure constructed with a normal Python function:&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;outer_func&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;lineno&quot;&gt; 2 &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;mi&quot;&gt;4&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 3 &lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;inner_func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;z&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;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;s2&quot;&gt;&amp;quot;x = &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{x}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;, y = &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{y}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;, z = &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{z}&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; 5 &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;x&lt;/span&gt; &lt;span class=&quot;o&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;z&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;lineno&quot;&gt; 6 &lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;inner_func&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;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;3&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;closure&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;outer_func&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&gt;&lt;span class=&quot;lineno&quot;&gt;10 &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;s2&quot;&gt;&amp;quot;closure({i+5}) = {closure(i+5)}&amp;quot;&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;outer_func()&lt;/code&gt; returns &lt;code&gt;inner_func()&lt;/code&gt;, a nested function that computes the sum of three arguments:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;x&lt;/code&gt;&lt;/strong&gt; is passed as an argument to &lt;code&gt;outer_func()&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;y&lt;/code&gt;&lt;/strong&gt; is a variable local to &lt;code&gt;outer_func()&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;z&lt;/code&gt;&lt;/strong&gt; is an argument passed to &lt;code&gt;inner_func()&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To test the behavior of &lt;code&gt;outer_func()&lt;/code&gt; and &lt;code&gt;inner_func()&lt;/code&gt;,  &lt;code&gt;outer_func()&lt;/code&gt; is invoked three times in a &lt;code&gt;for&lt;/code&gt; loop that prints 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;go&quot;&gt;x = 0, y = 4, z = 5&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;closure(5) = 9&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;x = 1, y = 4, z = 6&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;closure(6) = 11&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;x = 2, y = 4, z = 7&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;closure(7) = 13&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;On line 9 of the code, &lt;code&gt;inner_func()&lt;/code&gt; returned by the invocation of &lt;code&gt;outer_func()&lt;/code&gt; is bound to the name &lt;code&gt;closure&lt;/code&gt;. On line 5, &lt;code&gt;inner_func()&lt;/code&gt; captures &lt;code&gt;x&lt;/code&gt; and &lt;code&gt;y&lt;/code&gt; because it has access to its embedding environment, such that upon invocation of the closure, it is able to operate on the two free variables &lt;code&gt;x&lt;/code&gt; and &lt;code&gt;y&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Similarly, a &lt;code&gt;lambda&lt;/code&gt; can also be a closure. Here&amp;rsquo;s the same example with a Python lambda function:&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;outer_func&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;lineno&quot;&gt; 2 &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;mi&quot;&gt;4&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 3 &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;k&quot;&gt;lambda&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;z&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;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;z&lt;/span&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;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;3&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;hll&quot;&gt;    &lt;span class=&quot;n&quot;&gt;closure&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;outer_func&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&gt;&lt;span class=&quot;lineno&quot;&gt; 7 &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;s2&quot;&gt;&amp;quot;closure({i+5}) = {closure(i+5)}&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 you execute the code above, you obtain 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;go&quot;&gt;closure(5) = 9&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;closure(6) = 11&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;closure(7) = 13&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;On line 6, &lt;code&gt;outer_func()&lt;/code&gt; returns a lambda and assigns it to to the variable &lt;code&gt;closure&lt;/code&gt;. On line 3, the body of the lambda function references &lt;code&gt;x&lt;/code&gt; and &lt;code&gt;y&lt;/code&gt;. The variable &lt;code&gt;y&lt;/code&gt; is available at definition time, whereas &lt;code&gt;x&lt;/code&gt; is defined at runtime when &lt;code&gt;outer_func()&lt;/code&gt; is invoked.&lt;/p&gt;
&lt;p&gt;In this situation, both the normal function and the lambda behave similarly. In the next section, you&amp;rsquo;ll see a situation where the behavior of a lambda can be deceptive due to its evaluation time (definition time vs runtime).&lt;/p&gt;
&lt;h3 id=&quot;evaluation-time&quot;&gt;Evaluation Time&lt;/h3&gt;
&lt;p&gt;In some situations involving &lt;a href=&quot;https://realpython.com/courses/python-for-loop/&quot;&gt;loops&lt;/a&gt;, the behavior of a Python lambda function as a closure may be counterintuitive. It requires understanding when free variables are bound in the context of a lambda. The following examples demonstrate the difference when using a regular function vs using a Python lambda.&lt;/p&gt;
&lt;p&gt;Test the scenario first using a regular function:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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;lineno&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;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;wrap&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;n&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;gp&quot;&gt;... &lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;f&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;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;n&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;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;lineno&quot;&gt; 5 &lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;...&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 6 &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;s1&quot;&gt;&amp;#39;one&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;two&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;three&amp;#39;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 7 &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;funcs&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;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;n&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;lineno&quot;&gt; 9 &lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;... &lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;funcs&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;wrap&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;n&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;gp&quot;&gt;...&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;11 &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;f&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;funcs&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;gp&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;lineno&quot;&gt;13 &lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;...&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;14 &lt;/span&gt;&lt;span class=&quot;go&quot;&gt;one&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;15 &lt;/span&gt;&lt;span class=&quot;go&quot;&gt;two&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;16 &lt;/span&gt;&lt;span class=&quot;go&quot;&gt;three&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In a normal function, &lt;code&gt;n&lt;/code&gt; is evaluated at definition time, on line 9, when the function is added to the list: &lt;code&gt;funcs.append(wrap(n))&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Now, with the implementation of the same logic with a lambda function, observe the unexpected behavior:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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;lineno&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;numbers&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;one&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;two&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;three&amp;#39;&lt;/span&gt;
&lt;span class=&quot;lineno&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;funcs&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; 3 &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;n&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;lineno&quot;&gt; 4 &lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;... &lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;funcs&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;k&quot;&gt;lambda&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;n&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;gp&quot;&gt;...&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 6 &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;f&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;funcs&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;gp&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;lineno&quot;&gt; 8 &lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;...&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 9 &lt;/span&gt;&lt;span class=&quot;go&quot;&gt;three&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;10 &lt;/span&gt;&lt;span class=&quot;go&quot;&gt;three&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;11 &lt;/span&gt;&lt;span class=&quot;go&quot;&gt;three&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The unexpected result occurs because the free variable &lt;code&gt;n&lt;/code&gt;, as implemented, is bound at the execution time of the lambda expression. The Python lambda function on line 4 is a closure that captures &lt;code&gt;n&lt;/code&gt;, a free variable bound at runtime. At runtime, while invoking the function &lt;code&gt;f&lt;/code&gt; on line 7, the value of &lt;code&gt;n&lt;/code&gt; is &lt;code&gt;three&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;To overcome this issue, you can assign the free variable at definition time as follows:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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;lineno&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;numbers&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;one&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;two&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;three&amp;#39;&lt;/span&gt;
&lt;span class=&quot;lineno&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;funcs&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; 3 &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;n&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;lineno&quot;&gt; 4 &lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;... &lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;funcs&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;k&quot;&gt;lambda&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;n&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;n&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;gp&quot;&gt;...&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 6 &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;f&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;funcs&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;gp&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;lineno&quot;&gt; 8 &lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;...&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 9 &lt;/span&gt;&lt;span class=&quot;go&quot;&gt;one&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;10 &lt;/span&gt;&lt;span class=&quot;go&quot;&gt;two&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;11 &lt;/span&gt;&lt;span class=&quot;go&quot;&gt;three&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;A Python lambda function behaves like a normal function in regard to arguments. Therefore, a lambda parameter can be initialized with a default value: the parameter &lt;code&gt;n&lt;/code&gt; takes the outer &lt;code&gt;n&lt;/code&gt; as a default value. The Python lambda function could have been written as &lt;code&gt;lambda x=n: print(x)&lt;/code&gt; and have the same result.&lt;/p&gt;
&lt;p&gt;The Python lambda function is invoked without any argument on line 7, and it uses the default value &lt;code&gt;n&lt;/code&gt; set at definition time.&lt;/p&gt;
&lt;h3 id=&quot;testing-lambdas&quot;&gt;Testing Lambdas&lt;/h3&gt;
&lt;p&gt;Python lambdas can be tested similarly to regular functions. It&amp;rsquo;s possible to use both &lt;code&gt;unittest&lt;/code&gt; and &lt;code&gt;doctest&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;unittest&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;unittest&lt;/code&gt; module handles Python lambda functions similarly to regular functions:&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;unittest&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;addtwo&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;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;mi&quot;&gt;2&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;LambdaTest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;unittest&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TestCase&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;test_add_two&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;assertEqual&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;addtwo&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;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;test_add_two_point_two&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;assertEqual&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;addtwo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;2.2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;4.2&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;test_add_three&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;c1&quot;&gt;# Should fail&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;assertEqual&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;addtwo&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;6&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;unittest&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;verbosity&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;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;code&gt;LambdaTest&lt;/code&gt; defines a test case with three test methods, each of them exercising a test scenario for &lt;code&gt;addtwo()&lt;/code&gt; implemented as a lambda function. The execution of the Python file &lt;code&gt;lambda_unittest.py&lt;/code&gt; that contains &lt;code&gt;LambdaTest&lt;/code&gt; produces 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; python lambda_unittest.py
&lt;span class=&quot;go&quot;&gt;test_add_three (__main__.LambdaTest) ... FAIL&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;test_add_two (__main__.LambdaTest) ... ok&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;test_add_two_point_two (__main__.LambdaTest) ... ok&lt;/span&gt;

&lt;span class=&quot;go&quot;&gt;======================================================================&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;FAIL: test_add_three (__main__.LambdaTest)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;----------------------------------------------------------------------&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Traceback (most recent call last):&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  File &amp;quot;lambda_unittest.py&amp;quot;, line 18, in test_add_three&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;    self.assertEqual(addtwo(3), 6)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;AssertionError: 5 != 6&lt;/span&gt;

&lt;span class=&quot;go&quot;&gt;----------------------------------------------------------------------&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Ran 3 tests in 0.001s&lt;/span&gt;

&lt;span class=&quot;go&quot;&gt;FAILED (failures=1)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;As expected, we have two successful test cases and one failure for &lt;code&gt;test_add_three&lt;/code&gt;: the result is &lt;code&gt;5&lt;/code&gt;, but the expected result was &lt;code&gt;6&lt;/code&gt;. This failure is due to an intentional mistake in the test case. Changing the expected result from &lt;code&gt;6&lt;/code&gt; to &lt;code&gt;5&lt;/code&gt; will satisfy all the tests for &lt;code&gt;LambdaTest&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;doctest&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;doctest&lt;/code&gt; module extracts interactive Python code from &lt;code&gt;docstring&lt;/code&gt; to execute tests. Although the syntax of Python lambda functions does not support a typical &lt;code&gt;docstring&lt;/code&gt;, it is possible to assign a string to the &lt;code&gt;__doc__&lt;/code&gt; element of a named lambda:&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;addtwo&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;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;mi&quot;&gt;2&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;addtwo&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;vm&quot;&gt;__doc__&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;Add 2 to a number.&lt;/span&gt;
&lt;span class=&quot;s2&quot;&gt;    &amp;gt;&amp;gt;&amp;gt; addtwo(2)&lt;/span&gt;
&lt;span class=&quot;s2&quot;&gt;    4&lt;/span&gt;
&lt;span class=&quot;s2&quot;&gt;    &amp;gt;&amp;gt;&amp;gt; addtwo(2.2)&lt;/span&gt;
&lt;span class=&quot;s2&quot;&gt;    4.2&lt;/span&gt;
&lt;span class=&quot;s2&quot;&gt;    &amp;gt;&amp;gt;&amp;gt; addtwo(3) # Should fail&lt;/span&gt;
&lt;span class=&quot;s2&quot;&gt;    6&lt;/span&gt;
&lt;span class=&quot;s2&quot;&gt;    &amp;quot;&amp;quot;&amp;quot;&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;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;doctest&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;doctest&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;testmod&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;verbose&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;The &lt;code&gt;doctest&lt;/code&gt; in the doc comment of lambda &lt;code&gt;addtwo()&lt;/code&gt; describes the same test cases as in the previous section.&lt;/p&gt;
&lt;p&gt;When you execute the tests via &lt;code&gt;doctest.testmod()&lt;/code&gt;, you get 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; python lambda_doctest.py
&lt;span class=&quot;go&quot;&gt;Trying:&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;    addtwo(2)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Expecting:&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;    4&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;ok&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Trying:&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;    addtwo(2.2)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Expecting:&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;    4.2&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;ok&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Trying:&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;    addtwo(3) # Should fail&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Expecting:&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;    6&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;**********************************************************************&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;File &amp;quot;lambda_doctest.py&amp;quot;, line 16, in __main__.addtwo&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Failed example:&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;    addtwo(3) # Should fail&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Expected:&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;    6&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Got:&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;    5&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;1 items had no tests:&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;    __main__&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;**********************************************************************&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;1 items had failures:&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;   1 of   3 in __main__.addtwo&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;3 tests in 2 items.&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;2 passed and 1 failed.&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;***Test Failed*** 1 failures.&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The failed test results from the same failure explained in the execution of the unit tests in the previous section.&lt;/p&gt;
&lt;p&gt;You can add a &lt;code&gt;docstring&lt;/code&gt; to a Python lambda via an assignment to &lt;code&gt;__doc__&lt;/code&gt; to document a lambda function. Although possible, the Python syntax better accommodates &lt;code&gt;docstring&lt;/code&gt; for normal functions than lambda functions.&lt;/p&gt;
&lt;p&gt;For a comprehensive overview of unit testing in Python, you may want to refer to &lt;a href=&quot;https://realpython.com/python-testing/&quot;&gt;Getting Started With Testing in Python&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;lambda-expression-abuses&quot;&gt;Lambda Expression Abuses&lt;/h2&gt;
&lt;p&gt;Several examples in this article, if written in the context of professional Python code, would qualify as abuses.&lt;/p&gt;
&lt;p&gt;If you find yourself trying to overcome something that a lambda expression does not support, this is probably a sign that a normal function would be better suited. The &lt;code&gt;docstring&lt;/code&gt; for a lambda expression in the previous section is a good example. Attempting to overcome the fact that a Python lambda function does not support statements is another red flag.&lt;/p&gt;
&lt;p&gt;The next sections illustrate a few examples of lambda usages that should be avoided. Those examples might be situations where, in the context of Python lambda, the code exhibits the following pattern:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It doesn&amp;rsquo;t follow the Python style guide (PEP 8)&lt;/li&gt;
&lt;li&gt;It&amp;rsquo;s cumbersome and difficult to read.&lt;/li&gt;
&lt;li&gt;It&amp;rsquo;s unnecessarily clever at the cost of difficult readability.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;raising-an-exception&quot;&gt;Raising an Exception&lt;/h3&gt;
&lt;p&gt;Trying to raise an exception in a Python lambda should make you think twice. There are some clever ways to do so, but even something like the following is better to avoid:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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;throw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;raise&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ex&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;k&quot;&gt;lambda&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;throw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ne&quot;&gt;Exception&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;Something bad happened&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)))()&lt;/span&gt;
&lt;span class=&quot;gt&quot;&gt;Traceback (most recent call last):&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;File&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;&amp;lt;stdin&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;line&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;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;module&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;File&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;&amp;lt;stdin&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;line&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;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;lambda&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;File&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;&amp;lt;stdin&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;line&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;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;throw&lt;/span&gt;
&lt;span class=&quot;gr&quot;&gt;Exception&lt;/span&gt;: &lt;span class=&quot;n&quot;&gt;Something bad happened&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Because a statement is not syntactically correct in a Python lambda body, the workaround in the example above consists of abstracting the statement call with a dedicated function &lt;code&gt;throw()&lt;/code&gt;. Using this type of workaround should be avoided. If you encounter this type of code, you should consider refactoring the code to use a regular function.&lt;/p&gt;
&lt;h3 id=&quot;cryptic-style&quot;&gt;Cryptic Style&lt;/h3&gt;
&lt;p&gt;As in any programming languages, you will find Python code that can be difficult to read because of the style used. Lambda functions, due to their conciseness, can be conducive to writing code that is difficult to read.&lt;/p&gt;
&lt;p&gt;The following lambda example contains several bad style choices:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;lambda&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;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;k&quot;&gt;lambda&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;_&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;_&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;2&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;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;6&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;8&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;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;[0, 1, 1, 2, 2, 3, 3, 4, 4, 5]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The underscore (&lt;code&gt;_&lt;/code&gt;) refers to a variable that you don&amp;rsquo;t need to refer to explicitly. But in this example, three &lt;code&gt;_&lt;/code&gt; refer to different variables. An initial upgrade to this lambda code could be to name the variables:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;lambda&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;some_list&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;nb&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;lambda&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n&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;                                some_list)))([1,2,3,4,5,6,7,8,9,10])&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;[0, 1, 1, 2, 2, 3, 3, 4, 4, 5]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Admittedly, it&amp;rsquo;s still difficult to read. By still taking advantage of a &lt;code&gt;lambda&lt;/code&gt;, a regular function would go a long way to render this code more readable, spreading the logic over a few lines and function calls:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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;div_items&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;some_list&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;      div_by_two = lambda n: n // 2&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;      return map(div_by_two, some_list)&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;div_items&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;2&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;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;6&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;8&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;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])))&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;[0, 1, 1, 2, 2, 3, 3, 4, 4, 5]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This is still not optimal but shows you a possible path to make code, and Python lambda functions in particular, more readable. In &lt;a href=&quot;#alternatives-to-lambdas&quot;&gt;Alternatives to Lambdas&lt;/a&gt;, you&amp;rsquo;ll learn to replace &lt;code&gt;map()&lt;/code&gt; and &lt;code&gt;lambda&lt;/code&gt; with list comprehensions or generator expressions. This will drastically improve the readability of the code.&lt;/p&gt;
&lt;h3 id=&quot;python-classes&quot;&gt;Python Classes&lt;/h3&gt;
&lt;p&gt;You can but should not write class methods as Python lambda functions. The following example is perfectly legal Python code but exhibits unconventional Python code relying on &lt;code&gt;lambda&lt;/code&gt;. For example, instead of implementing &lt;code&gt;__str__&lt;/code&gt; as a regular function, it uses a &lt;code&gt;lambda&lt;/code&gt;. Similarly, &lt;code&gt;brand&lt;/code&gt; and &lt;code&gt;year&lt;/code&gt; are &lt;a href=&quot;https://docs.python.org/3/library/functions.html#property&quot;&gt;properties&lt;/a&gt; also implemented with lambda functions, instead of regular functions or decorators:&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;Car&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;Car with methods as lambda functions.&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;n&quot;&gt;brand&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;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;brand&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;brand&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;year&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;year&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;brand&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;property&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;lambda&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;nb&quot;&gt;getattr&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;s1&quot;&gt;&amp;#39;_brand&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
                     &lt;span class=&quot;k&quot;&gt;lambda&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;nb&quot;&gt;setattr&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;s1&quot;&gt;&amp;#39;_brand&amp;#39;&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;year&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;property&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;lambda&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;nb&quot;&gt;getattr&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;s1&quot;&gt;&amp;#39;_year&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
                    &lt;span class=&quot;k&quot;&gt;lambda&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;nb&quot;&gt;setattr&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;s1&quot;&gt;&amp;#39;_year&amp;#39;&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;fm&quot;&gt;__str__&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;bp&quot;&gt;self&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;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{self.brand}&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{self.year}&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# 1: error E731&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;honk&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;bp&quot;&gt;self&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;Honk!&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;     &lt;span class=&quot;c1&quot;&gt;# 2: error E731&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Running a tool like &lt;a href=&quot;http://flake8.pycqa.org/&quot;&gt;&lt;code&gt;flake8&lt;/code&gt;&lt;/a&gt;, a style guide enforcement tool, will display the following errors for &lt;code&gt;__str__&lt;/code&gt; and &lt;code&gt;honk&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;go&quot;&gt;E731 do not assign a lambda expression, use a def&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Although &lt;code&gt;flake8&lt;/code&gt; doesn&amp;rsquo;t point out an issue for the usage of the Python lambda functions in the properties, they are difficult to read and prone to error because of the usage of multiple strings like &lt;code&gt;&#39;_brand&#39;&lt;/code&gt; and &lt;code&gt;&#39;_year&#39;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Proper implementation of &lt;code&gt;__str__&lt;/code&gt; would be expected to be as follows:&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;__str__&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;k&quot;&gt;return&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;{self.brand}&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{self.year}&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;code&gt;brand&lt;/code&gt; would be written as follows:&lt;/p&gt;
&lt;div class=&quot;highlight python&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;nd&quot;&gt;@property&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;brand&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;k&quot;&gt;return&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;_brand&lt;/span&gt;

&lt;span class=&quot;nd&quot;&gt;@brand&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;setter&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;brand&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;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_brand&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;/pre&gt;&lt;/div&gt;

&lt;p&gt;As a general rule, in the context of code written in Python, prefer regular functions over lambda expressions. Nonetheless, there are cases that benefit from lambda syntax, as you will see in the next section.&lt;/p&gt;
&lt;h2 id=&quot;appropriate-uses-of-lambda-expressions&quot;&gt;Appropriate Uses of Lambda Expressions&lt;/h2&gt;
&lt;p&gt;Lambdas in Python tend to be the subject of controversies. Some of the arguments against lambdas in Python are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Issues with readability&lt;/li&gt;
&lt;li&gt;The imposition of a functional way of thinking&lt;/li&gt;
&lt;li&gt;Heavy syntax with the &lt;code&gt;lambda&lt;/code&gt; keyword&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Despite the heated debates questioning the mere existence of this feature in Python, lambda functions have properties that sometimes provide value to the Python language and to developers.&lt;/p&gt;
&lt;p&gt;The following examples illustrate scenarios where the use of lambda functions is not only suitable but encouraged in Python code.&lt;/p&gt;
&lt;h3 id=&quot;classic-functional-constructs&quot;&gt;Classic Functional Constructs&lt;/h3&gt;
&lt;p&gt;Lambda functions are regularly used with the built-in functions &lt;a href=&quot;https://docs.python.org/3/library/functions.html#map&quot;&gt;&lt;code&gt;map()&lt;/code&gt;&lt;/a&gt; and &lt;a href=&quot;https://docs.python.org/3/library/functions.html#filter&quot;&gt;&lt;code&gt;filter()&lt;/code&gt;&lt;/a&gt;, as well as &lt;a href=&quot;https://docs.python.org/3/library/functools.html?highlight=reduce#functools.reduce&quot;&gt;&lt;code&gt;functools.reduce()&lt;/code&gt;&lt;/a&gt;, exposed in the module &lt;a href=&quot;https://docs.python.org/3/library/functools.html&quot;&gt;&lt;code&gt;functools&lt;/code&gt;&lt;/a&gt;. The following three examples are respective illustrations of using those functions with lambda expressions as companions:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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;nb&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;lambda&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;upper&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;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;cow&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]))&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;[&amp;#39;CAT&amp;#39;, &amp;#39;DOG&amp;#39;, &amp;#39;COW&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;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;k&quot;&gt;lambda&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;s1&quot;&gt;&amp;#39;o&amp;#39;&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&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;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;cow&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]))&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;[&amp;#39;dog&amp;#39;, &amp;#39;cow&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;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;functools&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;reduce&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;reduce&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;lambda&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;acc&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;f&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{acc}&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt; | &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{x}&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;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;cow&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;&amp;#39;cat | dog | cow&amp;#39;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You may have to read code resembling the examples above, albeit with more relevant data. For that reason, it&amp;rsquo;s important to recognize those constructs. Nevertheless, those constructs have equivalent alternatives that are considered more Pythonic. In &lt;a href=&quot;#alternatives-to-lambdas&quot;&gt;Alternatives to Lambdas&lt;/a&gt;, you&amp;rsquo;ll learn how to convert higher-order functions and their accompanying lambdas into other more idiomatic forms.&lt;/p&gt;
&lt;h3 id=&quot;key-functions&quot;&gt;Key Functions&lt;/h3&gt;
&lt;p&gt;Key functions in Python are higher-order functions that take a parameter &lt;code&gt;key&lt;/code&gt; as a named argument. &lt;code&gt;key&lt;/code&gt; receives a function that can be a &lt;code&gt;lambda&lt;/code&gt;. This function directly influences the algorithm driven by the key function itself. Here are some key functions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;sort()&lt;/code&gt;:&lt;/strong&gt; list method&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;sorted()&lt;/code&gt;, &lt;code&gt;min()&lt;/code&gt;, &lt;code&gt;max()&lt;/code&gt;:&lt;/strong&gt; built-in functions&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;nlargest()&lt;/code&gt; and &lt;code&gt;nsmallest()&lt;/code&gt;:&lt;/strong&gt; in the Heap queue algorithm module &lt;code&gt;heapq&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Imagine that you want to sort a list of IDs represented as strings. Each ID is the &lt;a href=&quot;https://realpython.com/python-string-split-concatenate-join/&quot;&gt;concatenation&lt;/a&gt; of the string &lt;code&gt;id&lt;/code&gt; and a number. Sorting this list with the built-in function &lt;code&gt;sorted()&lt;/code&gt;, by default, uses a lexicographic order as the elements in the list are strings.&lt;/p&gt;
&lt;p&gt;To influence the sorting execution, you can assign a lambda to the named argument &lt;code&gt;key&lt;/code&gt;, such that the sorting will use the number associated with the ID:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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;ids&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;id1&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;id2&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;id30&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;id3&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;id22&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;id100&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;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;nb&quot;&gt;sorted&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ids&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# Lexicographic sort&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;go&quot;&gt;[&amp;#39;id1&amp;#39;, &amp;#39;id2&amp;#39;, &amp;#39;id30&amp;#39;, &amp;#39;id3&amp;#39;, &amp;#39;id22&amp;#39;, &amp;#39;id100&amp;#39;]&lt;/span&gt;
&lt;span class=&quot;hll&quot;&gt;&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sorted_ids&lt;/span&gt; &lt;span class=&quot;o&quot;&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;ids&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;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;int&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;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:]))&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# Integer sort&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;sorted_ids&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;[&amp;#39;id1&amp;#39;, &amp;#39;id2&amp;#39;, &amp;#39;id3&amp;#39;, &amp;#39;id22&amp;#39;, &amp;#39;id30&amp;#39;, &amp;#39;id100&amp;#39;]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id=&quot;ui-frameworks&quot;&gt;UI Frameworks&lt;/h3&gt;
&lt;p&gt;UI frameworks like &lt;a href=&quot;https://docs.python.org/3/library/tk.html&quot;&gt;Tkinter&lt;/a&gt;, &lt;a href=&quot;https://wxpython.org/&quot;&gt;wxPython&lt;/a&gt;, or .NET Windows Forms with &lt;a href=&quot;https://ironpython.net/&quot;&gt;IronPython&lt;/a&gt; take advantage of lambda functions for mapping actions in response to UI events.&lt;/p&gt;
&lt;p&gt;The naive Tkinter program below demonstrates the usage of a &lt;code&gt;lambda&lt;/code&gt; assigned to the command of the &lt;em&gt;Reverse&lt;/em&gt; button:&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;tkinter&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;tk&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;sys&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;window&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tk&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Tk&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;window&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;grid_columnconfigure&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;weight&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;n&quot;&gt;window&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;Lambda&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;window&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;geometry&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;300x100&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;label&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tk&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Label&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;window&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;s2&quot;&gt;&amp;quot;Lambda Calculus&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;label&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;grid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;column&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;n&quot;&gt;row&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;n&quot;&gt;button&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tk&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Button&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;window&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;s2&quot;&gt;&amp;quot;Reverse&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;command&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;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;label&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;configure&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;label&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cget&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;text&amp;quot;&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&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;button&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;grid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;column&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;n&quot;&gt;row&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;n&quot;&gt;window&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mainloop&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Clicking the button &lt;em&gt;Reverse&lt;/em&gt; fires an event that triggers the lambda function, changing the label from &lt;em&gt;Lambda Calculus&lt;/em&gt; to &lt;em&gt;suluclaC adbmaL&lt;/em&gt;*:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://files.realpython.com/media/tkinter_lambda.be4b6259769e.gif&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/tkinter_lambda.be4b6259769e.gif&quot; width=&quot;295&quot; height=&quot;127&quot; srcset=&quot;https://robocrop.realpython.net/?url=https%3A//files.realpython.com/media/tkinter_lambda.be4b6259769e.gif&amp;amp;w=73&amp;amp;sig=7dc06655bb5fdf37302be8b963b77bf66990cc10 73w, https://robocrop.realpython.net/?url=https%3A//files.realpython.com/media/tkinter_lambda.be4b6259769e.gif&amp;amp;w=147&amp;amp;sig=afc9b30610c3cb0da292b55a24d8f2c5270d483f 147w, https://files.realpython.com/media/tkinter_lambda.be4b6259769e.gif 295w&quot; sizes=&quot;75vw&quot; alt=&quot;Animated TkInter Windows demonstrating the action of the button to the text&quot;/&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Both wxPython and IronPython on the .NET platform share a similar approach for handling events. Note that &lt;code&gt;lambda&lt;/code&gt; is one way to handle firing events, but a function may be used for the same purpose. It ends up being self-contained and less verbose to use a &lt;code&gt;lambda&lt;/code&gt; when the amount of code needed is very short.&lt;/p&gt;
&lt;p&gt;To explore wxPython, check out &lt;a href=&quot;https://realpython.com/python-gui-with-wxpython/&quot;&gt;How to Build a Python GUI Application With wxPython&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;python-interpreter&quot;&gt;Python Interpreter&lt;/h3&gt;
&lt;p&gt;When you&amp;rsquo;re playing with Python code in the interactive interpreter, Python lambda functions are often a blessing. It&amp;rsquo;s easy to craft a quick one-liner function to explore some snippets of code that will never see the light of day outside of the interpreter. The lambdas written in the interpreter, for the sake of speedy discovery, are like scrap paper that you can throw away after use.&lt;/p&gt;
&lt;h3 id=&quot;timeit&quot;&gt;&lt;code&gt;timeit&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;In the same spirit as the experimentation in the Python interpreter, the module &lt;code&gt;timeit&lt;/code&gt; provides functions to time small code fragments. &lt;code&gt;timeit.timeit()&lt;/code&gt; in particular can be called directly, passing some Python code in a string. Here&amp;rsquo;s an example:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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;timeit&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;timeit&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;timeit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;factorial(999)&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;from math import factorial&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;number&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;go&quot;&gt;0.0013087529951008037&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;When the statement is passed as a string, &lt;code&gt;timeit()&lt;/code&gt; needs the full context. In the example above, this is provided by the second argument that sets up the environment needed by the main function to be timed. Not doing so would raise a &lt;code&gt;NameError&lt;/code&gt; exception.&lt;/p&gt;
&lt;p&gt;Another approach is to use a &lt;code&gt;lambda&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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;math&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;factorial&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;timeit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;lambda&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;factorial&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;999&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;number&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;go&quot;&gt;0.0012704220062005334&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This solution is cleaner, more readable, and quicker to type in the interpreter. Although the execution time was slightly less for the &lt;code&gt;lambda&lt;/code&gt; version, executing the functions again may show a slight advantage for the &lt;code&gt;string&lt;/code&gt; version. The execution time of the &lt;code&gt;setup&lt;/code&gt; is excluded from the overall execution time and shouldn&amp;rsquo;t have any impact on the result.&lt;/p&gt;
&lt;h3 id=&quot;monkey-patching&quot;&gt;Monkey Patching&lt;/h3&gt;
&lt;p&gt;For testing, it&amp;rsquo;s sometimes necessary to rely on repeatable results, even if during the normal execution of a given software, the corresponding results are expected to differ, or even be totally random.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s say you want to test a function that, at runtime, handles random values. But, during the testing execution, you need to assert against predictable values in a repeatable manner. The following example shows how, with a &lt;code&gt;lambda&lt;/code&gt; function, monkey patching can help you:&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;contextlib&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;contextmanager&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;secrets&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;gen_token&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;Generate a random token.&amp;quot;&amp;quot;&amp;quot;&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;s1&quot;&gt;&amp;#39;TOKEN_{secrets.token_hex(8)}&amp;#39;&lt;/span&gt;

&lt;span class=&quot;nd&quot;&gt;@contextmanager&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;mock_token&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;Context manager to monkey patch the secrets.token_hex&lt;/span&gt;
&lt;span class=&quot;sd&quot;&gt;    function during testing.&lt;/span&gt;
&lt;span class=&quot;sd&quot;&gt;    &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;default_token_hex&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;secrets&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;token_hex&lt;/span&gt;
&lt;span class=&quot;hll&quot;&gt;    &lt;span class=&quot;n&quot;&gt;secrets&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;token_hex&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;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;feedfacecafebeef&amp;#39;&lt;/span&gt;
&lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;yield&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;secrets&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;token_hex&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;default_token_hex&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;test_gen_key&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;Test the random token.&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mock_token&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;assert&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;gen_token&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;f&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;TOKEN_{&amp;#39;feedfacecafebeef&amp;#39;}&amp;quot;&lt;/span&gt;

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

&lt;p&gt;A context manager helps with insulating the operation of monkey patching a function from the standard library (&lt;a href=&quot;https://docs.python.org/3/library/secrets.html#module-secrets&quot;&gt;&lt;code&gt;secrets&lt;/code&gt;&lt;/a&gt;, in this example). The lambda function assigned to &lt;code&gt;secrets.token_hex()&lt;/code&gt; substitutes the default behavior by returning a static value. &lt;/p&gt;
&lt;p&gt;This allows testing any function depending on &lt;code&gt;token_hex()&lt;/code&gt; in a predictable fashion. Prior to exiting from the context manager, the default behavior of &lt;code&gt;token_hex()&lt;/code&gt; is reestablished to eliminate any unexpected side effects that would affect other areas of the testing that may depend on the default behavior of &lt;code&gt;token_hex()&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Unit test frameworks like &lt;code&gt;unittest&lt;/code&gt; and &lt;code&gt;pytest&lt;/code&gt; take this concept to a higher level of sophistication.&lt;/p&gt;
&lt;p&gt;With &lt;code&gt;pytest&lt;/code&gt;, still using a &lt;code&gt;lambda&lt;/code&gt; function, the same example becomes more elegant and concise :&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;secrets&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;gen_token&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;f&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;TOKEN_{secrets.token_hex(8)}&amp;#39;&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;test_gen_key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;monkeypatch&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;monkeypatch&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;setattr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;secrets.token_hex&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;lambda&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;s1&quot;&gt;&amp;#39;feedfacecafebeef&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;assert&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;gen_token&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;f&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;TOKEN_{&amp;#39;feedfacecafebeef&amp;#39;}&amp;quot;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;With the &lt;a href=&quot;https://docs.pytest.org/en/latest/monkeypatch.html&quot;&gt;pytest &lt;code&gt;monkeypatch&lt;/code&gt; fixture&lt;/a&gt;, &lt;code&gt;secrets.token_hex()&lt;/code&gt; is overwritten with a lambda that will return a deterministic value, &lt;code&gt;feedfacecafebeef&lt;/code&gt;, allowing to validate the test. The pytest &lt;code&gt;monkeypatch&lt;/code&gt; fixture allows you to control the scope of the override. In the example above, invoking &lt;code&gt;secrets.token_hex()&lt;/code&gt; in subsequent tests, without using monkey patching, would execute the normal implementation of this function.&lt;/p&gt;
&lt;p&gt;Executing the &lt;code&gt;pytest&lt;/code&gt; test gives the following result:&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; pytest test_token.py -v
&lt;span class=&quot;go&quot;&gt;============================= test session starts ==============================&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;platform linux -- Python 3.7.2, pytest-4.3.0, py-1.8.0, pluggy-0.9.0&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;cachedir: .pytest_cache&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;rootdir: /home/andre/AB/tools/bpython, inifile:&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;collected 1 item&lt;/span&gt;

&lt;span class=&quot;go&quot;&gt;test_token.py::test_gen_key PASSED                                       [100%]&lt;/span&gt;

&lt;span class=&quot;go&quot;&gt;=========================== 1 passed in 0.01 seconds ===========================&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The test passes as we validated that the &lt;code&gt;gen_token()&lt;/code&gt; was exercised, and the results were the expected ones in the context of the test.&lt;/p&gt;
&lt;h2 id=&quot;alternatives-to-lambdas&quot;&gt;Alternatives to Lambdas&lt;/h2&gt;
&lt;p&gt;While there are great reasons to use &lt;code&gt;lambda&lt;/code&gt;, there are instances where its use is frowned upon. So what are the alternatives?&lt;/p&gt;
&lt;p&gt;Higher-order functions like &lt;code&gt;map()&lt;/code&gt;, &lt;code&gt;filter()&lt;/code&gt;, and &lt;code&gt;functools.reduce()&lt;/code&gt; can be converted to more elegant forms with slight twists of creativity, in particular with list comprehensions or generator expressions.&lt;/p&gt;
&lt;p&gt;Watch &lt;a href=&quot;https://realpython.com/courses/using-list-comprehensions-effectively/&quot;&gt;Using List Comprehensions Effectively&lt;/a&gt; to learn more about list comprehensions.&lt;/p&gt;
&lt;h3 id=&quot;map&quot;&gt;Map&lt;/h3&gt;
&lt;p&gt;The built-in function &lt;code&gt;map()&lt;/code&gt; takes a function as a first argument and applies it to each of the elements of its second argument, an &lt;strong&gt;iterable&lt;/strong&gt;. Examples of iterables are strings, lists, and tuples. For more information on iterables and iterators, check out &lt;a href=&quot;https://realpython.com/lessons/looping-over-iterables/&quot;&gt;Iterables and Iterators&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;map()&lt;/code&gt; returns an iterator corresponding to the transformed collection. As an example, if you wanted to transform a list of strings to a new list with each string capitalized, you could use &lt;code&gt;map()&lt;/code&gt;, as follows:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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;nb&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;lambda&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;capitalize&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;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;cow&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]))&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;[&amp;#39;Cat&amp;#39;, &amp;#39;Dog&amp;#39;, &amp;#39;Cow&amp;#39;]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You need to invoke &lt;code&gt;list()&lt;/code&gt; to convert the iterator returned by &lt;code&gt;map()&lt;/code&gt; into an expanded list that can be displayed in the Python shell interpreter.&lt;/p&gt;
&lt;p&gt;Using a list comprehension eliminates the need for defining and invoking the lambda function:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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;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;capitalize&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;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;cow&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]]&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;[&amp;#39;Cat&amp;#39;, &amp;#39;Dog&amp;#39;, &amp;#39;Cow&amp;#39;]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id=&quot;filter&quot;&gt;Filter&lt;/h3&gt;
&lt;p&gt;The built-in function &lt;code&gt;filter()&lt;/code&gt;, another classic functional construct, can be converted into a list comprehension. It takes a &lt;a href=&quot;https://en.wikipedia.org/wiki/Predicate_(mathematical_logic)&quot;&gt;predicate&lt;/a&gt; as a first argument and an iterable as a second argument. It builds an iterator containing all the elements of the initial collection that satisfies the predicate function. Here&amp;rsquo;s an example that filters all the even numbers in a given list of integers:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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;even&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;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;mi&quot;&gt;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;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;even&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;11&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)))&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;[0, 2, 4, 6, 8, 10]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Note that &lt;code&gt;filter()&lt;/code&gt; returns an iterator, hence the need to invoke the built-in type &lt;code&gt;list&lt;/code&gt; that constructs a list given an iterator.&lt;/p&gt;
&lt;p&gt;The implementation leveraging the list comprehension construct gives the following:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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;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;nb&quot;&gt;range&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;k&quot;&gt;if&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;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;go&quot;&gt;[0, 2, 4, 6, 8, 10]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id=&quot;reduce&quot;&gt;Reduce&lt;/h3&gt;
&lt;p&gt;Since Python 3, &lt;code&gt;reduce()&lt;/code&gt; has bgone from a built-in function to a &lt;code&gt;functools&lt;/code&gt; module function. As &lt;code&gt;map()&lt;/code&gt; and &lt;code&gt;filter()&lt;/code&gt;, its first two arguments are respectively a function and an iterable. It may also take an initializer as a third argument that is used as the initial value of the resulting accumulator. For each element of the iterable, &lt;code&gt;reduce()&lt;/code&gt; applies the function and accumulates the result that is returned when the iterable is exhausted.&lt;/p&gt;
&lt;p&gt;To apply &lt;code&gt;reduce()&lt;/code&gt; to a list of pairs and calculate the sum of the first item of each pair, you could write this:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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;functools&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;pairs&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;s1&quot;&gt;&amp;#39;a&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;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;b&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;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;c&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;n&quot;&gt;functools&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;reduce&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;lambda&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;acc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pair&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;acc&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pair&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;pairs&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;6&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;A more idiomatic approach using a &lt;a href=&quot;https://www.python.org/dev/peps/pep-0289/&quot;&gt;generator expression&lt;/a&gt;, as an argument to &lt;code&gt;sum()&lt;/code&gt; in the example, is the following:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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;pairs&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;s1&quot;&gt;&amp;#39;a&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;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;b&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;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;c&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;sum&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;mi&quot;&gt;0&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;pairs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;6&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;A slightly different and possibly cleaner solution removes the need to explicitly access the first element of the pair and instead use unpacking:&lt;/p&gt;
&lt;div class=&quot;highlight python repl&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;pairs&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;s1&quot;&gt;&amp;#39;a&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;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;b&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;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;c&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;sum&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;p&quot;&gt;,&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;n&quot;&gt;pairs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;6&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The use of underscore (&lt;code&gt;_&lt;/code&gt;) is a Python convention indicating that you can ignore the second value of the pair.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;sum()&lt;/code&gt; takes a unique argument, so the generator expression does not need to be in parentheses.&lt;/p&gt;
&lt;h2 id=&quot;are-lambdas-pythonic-or-not&quot;&gt;Are Lambdas Pythonic or Not?&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.python.org/dev/peps/pep-0008/&quot;&gt;PEP 8&lt;/a&gt;, which is the style guide for Python code, reads:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Always use a def statement instead of an assignment statement that binds a lambda expression directly to an identifier. (&lt;a href=&quot;https://www.python.org/dev/peps/pep-0008/#programming-recommendations&quot;&gt;Source&lt;/a&gt;)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This strongly discourages using lambda bound to an identifier, mainly where functions should be used and have more benefits. PEP 8 does not mention other usages of &lt;code&gt;lambda&lt;/code&gt;. As you have seen in the previous sections, lambda functions may certainly have good uses, although they are limited.&lt;/p&gt;
&lt;p&gt;A possible way to answer the question is that lambda functions are perfectly Pythonic if there is nothing more Pythonic available. I&amp;rsquo;m staying away from defining what &amp;ldquo;Pythonic&amp;rdquo; means, leaving you with the definition that best suits your mindset, as well as your personal or your team&amp;rsquo;s coding style.&lt;/p&gt;
&lt;p&gt;Beyond the narrow scope of Python &lt;code&gt;lambda&lt;/code&gt;, &lt;a href=&quot;https://realpython.com/python-pep8/&quot;&gt;How to Write Beautiful Python Code With PEP 8&lt;/a&gt; is a great resource that you may want to check out regarding code style in Python.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;You now know how to use Python &lt;code&gt;lambda&lt;/code&gt; functions and can:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Write Python lambdas and use anonymous functions&lt;/li&gt;
&lt;li&gt;Choose wisely between lambdas or normal Python functions&lt;/li&gt;
&lt;li&gt;Avoid excessive use of lambdas&lt;/li&gt;
&lt;li&gt;Use lambdas with higher-order functions or Python key functions&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you have a penchant for mathematics, you may have some fun exploring the fascinating world of &lt;a href=&quot;https://en.wikipedia.org/wiki/Lambda_calculus&quot;&gt;lambda calculus&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Python lambdas are like salt. A pinch in your spam, ham, and eggs will enhance the flavors, but too much will spoil the dish.&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 Python programming language, named after Monty Python, prefers to use &lt;a href=&quot;https://en.wikipedia.org/wiki/Spam_%28Monty_Python%29&quot;&gt;&lt;code&gt;spam&lt;/code&gt;&lt;/a&gt;, &lt;code&gt;ham&lt;/code&gt;, and &lt;code&gt;eggs&lt;/code&gt; as metasyntactic variables, instead of the traditional &lt;code&gt;foo&lt;/code&gt;, &lt;code&gt;bar&lt;/code&gt;, and &lt;code&gt;baz&lt;/code&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>How to Publish Your Own Python Package to PyPI</title>
      <id>https://realpython.com/courses/how-to-publish-your-own-python-package-pypi/</id>
      <link href="https://realpython.com/courses/how-to-publish-your-own-python-package-pypi/"/>
      <updated>2019-06-18T14:00:00+00:00</updated>
      <summary>Learn how to create a Python package for your project and how to publish it to PyPI, the Python Package Repository with this step-by-step course. Quickly get up to speed on everything from naming your package to configuring it using setup.py.</summary>
      <content type="html">
        &lt;p&gt;Learn how to create a Python package for your project and how to publish it to PyPI, the Python Package Repository with this step-by-step course. Quickly get up to speed on everything from naming your package to configuring it using &lt;code&gt;setup.py&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>Python Community Interview With Marlene Mhangami</title>
      <id>https://realpython.com/interview-marlene-mhangami/</id>
      <link href="https://realpython.com/interview-marlene-mhangami/"/>
      <updated>2019-06-17T14:00:00+00:00</updated>
      <summary>Join us as we chat with Marlene Mhangami. She&#39;s a PSF Director and the co-founder of ZimboPy, a Zimbabwean non-profit that empowers women to pursue careers in tech. She&#39;s also organizing the very first PyCon Africa.</summary>
      <content type="html">
        &lt;p&gt;We are joined today by Marlene Mhangami. &lt;a href=&quot;https://twitter.com/marlene_zw&quot;&gt;Marlene&lt;/a&gt; is a passionate Pythonista who is not only using tech to facilitate social change and empower Zimbabwean women but is also the chair of the very first &lt;a href=&quot;https://africa.pycon.org/&quot;&gt;PyCon Africa&lt;/a&gt;. Join me as we talk about her non-traditional start in tech, as well as her passion for using technology to create social change for good.&lt;/p&gt;
&lt;p class=&quot;mt-5&quot;&gt;&lt;strong&gt;Ricky:&lt;/strong&gt; &lt;em&gt;Welcome, Marlene! I&amp;rsquo;m so glad you could join me for this interview. Let&amp;rsquo;s start with the usual first question. How&amp;rsquo;d you get into programming, and when did you start using Python?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://files.realpython.com/media/IMG_9845.a13bccafc9ec.jpg&quot; target=&quot;_blank&quot;&gt;&lt;img class=&quot;img-fluid w-25 float-right ml-3 rounded-circle&quot; src=&quot;https://files.realpython.com/media/IMG_9845.a13bccafc9ec.jpg&quot; width=&quot;1923&quot; height=&quot;2207&quot; srcset=&quot;https://robocrop.realpython.net/?url=https%3A//files.realpython.com/media/IMG_9845.a13bccafc9ec.jpg&amp;amp;w=480&amp;amp;sig=82a21586db37d56365319d2296719011e3d72cef 480w, https://robocrop.realpython.net/?url=https%3A//files.realpython.com/media/IMG_9845.a13bccafc9ec.jpg&amp;amp;w=961&amp;amp;sig=e91c5a935bc742b737577261686abb179de92862 961w, https://files.realpython.com/media/IMG_9845.a13bccafc9ec.jpg 1923w&quot; sizes=&quot;75vw&quot; alt=&quot;Marlene Mhangami&quot;/&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Marlene:&lt;/strong&gt; Well, my background is in molecular biology, so in college, although I had some interaction with code, it wasn&amp;rsquo;t really something I used regularly. I&amp;rsquo;ve always been interested in technology and the impact it has on the world, but growing up I didn&amp;rsquo;t really have anyone to introduce me to the concept of coding. We had one computer that we shared in my house, and my brothers were super into gaming. They were on it all the time.&lt;/p&gt;
&lt;p&gt;In high school, I took a computer class, but my teachers, who I&amp;rsquo;m sure were really nice people, didn&amp;rsquo;t go much further than the basics of using Microsoft Office and having us memorize names of different parts of hardware. So, in general, I focused more on life and physical sciences, and I&amp;rsquo;m still really interested in those fields today.&lt;/p&gt;
&lt;p&gt;I studied for a bit in the United States for college, and I remember coming home one summer and being really aware of how different Zimbabwe was from the U.S. From really small cultural differences like how people address conflict (which is something I&amp;rsquo;m still trying to figure out with my US friends) to much more impactful things like access to knowledge and education. &lt;/p&gt;
&lt;p&gt;I decided I wanted to start being more involved with my local community, and for some reason, I decided that I wanted to leverage technology to help me do that. I also had a really vivid dream that made me re-evaluate what I was doing with my life. &lt;/p&gt;
&lt;p&gt;After googling around and actually organizing a meetup, I got introduced to one of my co-founders, &lt;a href=&quot;https://www.linkedin.com/in/ronald-t-maravanyika-78221131/&quot;&gt;Ronald Maravanykia&lt;/a&gt;, who was at the time running a &lt;a href=&quot;https://djangogirls.org/&quot;&gt;Django girls&lt;/a&gt; workshop in Harare. He introduced me to Python as a great educational tool for teaching programming to people who don&amp;rsquo;t have a computer science background. That was almost three years ago, and I&amp;rsquo;m super grateful Python ended up being the language I chose to focus on. It&amp;rsquo;s really great!&lt;/p&gt;
&lt;p class=&quot;mt-5&quot;&gt;&lt;strong&gt;Ricky:&lt;/strong&gt; &lt;em&gt;As a Zimbabwean, you are passionate about empowering Zimbabwean women in tech and helping today&amp;rsquo;s young girls pursue a career in tech. So much so that you are the programs director at the non-profit ZimboPy?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Marlene:&lt;/strong&gt; Yes, as I mentioned earlier, using technology to create social change for good is something that&amp;rsquo;s consistently at the forefront of my mind. My co-founders and I decided to create &lt;a href=&quot;https://www.zimbopy.com/&quot;&gt;ZimboPy&lt;/a&gt; as a way to give girls in Zim access to knowledge and experiences they wouldn&amp;rsquo;t necessarily get anywhere else in the country. &lt;/p&gt;
&lt;p&gt;I think for me, the end goal is to create a model where we introduce girls to programming, and if they enjoy it, offering them a pathway to get jobs in the field. The tech world is not perfect, but unlike most fields, there are ways that you can by-pass traditional gatekeepers and be successful regardless of whether or not you have the privilege of receiving formal higher education. &lt;/p&gt;
&lt;p&gt;We are still a small non-profit, and I&amp;rsquo;m learning new things every day, but we&amp;rsquo;ve had some great success stories that give me so much hope! Also, our mentorship weeks, where we introduce girls to women who are doing incredible things in the field and help them build something new, are my favorite thing to do all year! We&amp;rsquo;ve had incredible women like Ashley McNamara and Emily Freeman speak. It&amp;rsquo;s always so much fun!&lt;/p&gt;
&lt;p class=&quot;mt-5&quot;&gt;&lt;strong&gt;Ricky:&lt;/strong&gt; &lt;em&gt;You are one of the 13 members of the &lt;a href=&quot;https://www.python.org/psf/&quot;&gt;Python Software Foundation&amp;rsquo;s (PSF)&lt;/a&gt; Board of Directors. How did you come to be involved with the PSF, and what do you think is the biggest challenge as we look towards 2020 and beyond?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Marlene:&lt;/strong&gt; I&amp;rsquo;m actually up for re-election this year, so hopefully, I&amp;rsquo;ll still be on the board for 2020. I really had such a positive experience with it so far! &lt;/p&gt;
&lt;p&gt;I was actually introduced to the PSF by &lt;a href=&quot;https://twitter.com/loooorenanicole&quot;&gt;Lorena Mesa&lt;/a&gt;, who was volunteering to speak at one of our ZimboPy mentorship weeks in early 2017. She was on the board at the time, and we spoke about it around the time when elections were coming up. She really felt that I would be a great addition to the board. At that time, no one from Africa had ever held a seat, so she was super encouraging. &lt;/p&gt;
&lt;p&gt;I remember looking through the list of the nominees and thinking that I didn&amp;rsquo;t belong there. I had done some work with the local Python community in Zimbabwe, but I felt really intimidated by everyone&amp;rsquo;s profiles. I ended up agreeing to let Lorena nominate me, mainly because I had nothing to lose, haha! Surprisingly, I was voted in, which I think is purely a testament to the Python community&amp;rsquo;s commitment to diversity and global representation. &lt;/p&gt;
&lt;p&gt;So many changes have taken place in the last few years: the formation of the steering council, the exponential growth of PyCon, and the spread of the language globally. All of these are things we&amp;rsquo;ve been able to discuss as a board. &lt;/p&gt;
&lt;p&gt;I think defining the biggest challenge is tricky because it genuinely depends on each individual&amp;rsquo;s perspective. There are Directors on the board who are infinitely more technical than I am, and they can probably speak to all sorts of challenges on the future of Python from a more technical perspective. &lt;/p&gt;
&lt;p&gt;For me, my focus is to help the growth of Python and its community to be as inclusive and representative as possible. I recently became the board&amp;rsquo;s communications co-chair, along with Lorena, and have been working with the blogging team. I&amp;rsquo;d like to see an increase in the representation of voices from communities around the world, maybe one day having blog posts and content on the official site in various languages. &lt;/p&gt;
&lt;p&gt;All of these are things I feel are important and a challenge that we have to tackle well. &lt;/p&gt;
&lt;p class=&quot;mt-5&quot;&gt;&lt;strong&gt;Ricky:&lt;/strong&gt; &lt;em&gt;I had the good fortune to meet you in person at PyCon 2019. It was your first PyCon (mine, too). How was your experience there? What was the standout moment for you?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Marlene:&lt;/strong&gt; I genuinely loved Pycon 2019, and of course meeting you, Ricky, and the rest of the &lt;em&gt;Real Python&lt;/em&gt; team! I&amp;rsquo;ve been to several PyCons around Africa and other parts of the world, but PyCon US is definitely a unique experience. &lt;/p&gt;
&lt;p&gt;One of my favorite things about the conference was how friendly and laid back everyone was. I&amp;rsquo;d literally pass by people that I follow on Twitter, who have done amazing things, and they&amp;rsquo;d just be sitting there, eating a sandwich! I&amp;rsquo;m being a little funny here, but honestly, everyone was so welcoming and fun. I still can&amp;rsquo;t fully wrap my head around it.&lt;/p&gt;
&lt;p&gt;I had so many standout moments, but I think I&amp;rsquo;d say Sha Wallace and Jessica Meckeller&amp;rsquo;s joint keynote was out of this world. I was tearing up because it&amp;rsquo;s such a great example of how we as a community can create positive change! I took away so many notes from that talk that I&amp;rsquo;d like to implement here in Zimbabwe. &lt;/p&gt;
&lt;p&gt;This is an additional thing, I know, but I&amp;rsquo;d also like to say that I had so many standout moments outside the convention center, like having dinner with people from around the world and going to the local art gallery and trying bubble tea, also generally just wandering about the city. I had the best time, and I&amp;rsquo;m really looking forward to Pittsburg in 2020!&lt;/p&gt;
&lt;p class=&quot;mt-5&quot;&gt;&lt;strong&gt;Ricky:&lt;/strong&gt; &lt;em&gt;If my memory serves right, at the end of PyCon, &lt;a href=&quot;https://twitter.com/nnja/status/1126514450830385157&quot;&gt;Microsoft and Adafruit donated a bunch of Circuit Playground Lunchbox Kits&lt;/a&gt; for you to take back to the girls you mentor in Zimbabwe. I&amp;rsquo;m curious if you managed to put them to use yet? Or what your plans are, outside of using them to teach them how to write some CircuitPython?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Marlene:&lt;/strong&gt; Yes! That was another standout moment (to add to the twenty others above, haha). I got to chat with &lt;a href=&quot;https://twitter.com/nnja&quot;&gt;Nina Zakharenko&lt;/a&gt; and &lt;a href=&quot;https://twitter.com/kattni&quot;&gt;Katni from Adafruit&lt;/a&gt;, who are some of the loveliest human beings I&amp;rsquo;ve ever met! We had dinner together at some point and afterwards, they decided to donate the kits for me to bring back home and use for our ZimboPy programs. &lt;/p&gt;
&lt;p&gt;I only recently got back to Zimbabwe, and I&amp;rsquo;ve started to play around with the kits myself. The plan at the moment is to host a workshop specifically centered around CircuitPython to show the girls that they can be playful and have fun while they code. I&amp;rsquo;m super pumped about it! &lt;/p&gt;
&lt;p&gt;I was also talking to Kat about the potential of me hosting a tutorial at PyCon Africa with the Adafruit boards, similar to what she was demoing at the Microsoft booth. If I feel confident enough to do it by July, I think that&amp;rsquo;s something attendees at the conference should look out for! &lt;/p&gt;
&lt;p class=&quot;mt-5&quot;&gt;&lt;strong&gt;Ricky:&lt;/strong&gt; &lt;em&gt;As if all the community work you do already isn&amp;rsquo;t enough, you&amp;rsquo;re also the organizer of the very first PyCon Africa! How&amp;rsquo;s the planning coming on? Can you share any details?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Marlene:&lt;/strong&gt; I&amp;rsquo;m really excited that we&amp;rsquo;re in the final stages of planning for the conference. PyCon Africa is the first regional / pan-African gathering of the Python community! We have a great organizing committee, with people who have helped organize PyCons in Nigeria, Ghana, Namibia, Uganda, South Africa, and even the UK, so in that respect, I&amp;rsquo;ve been really lucky to land on this team. &lt;/p&gt;
&lt;p&gt;The response from the global Python community has also been really encouraging. &lt;em&gt;Real Python&lt;/em&gt; is actually &lt;a href=&quot;https://africa.pycon.org/our-sponsors/&quot;&gt;one of our sponsors&lt;/a&gt;, which is amazing. Shout out to you! I think we&amp;rsquo;re moving in the right direction.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m this year&amp;rsquo;s chair, and although everything is running smoothly so far, I&amp;rsquo;ve been surprised by how all-consuming the process of planning can feel at times. Each time I look up it&amp;rsquo;s as if 3 months have passed! At PyCon US, I was speaking to a few other regional conference organizers and was glad to find I wasn&amp;rsquo;t the only one that felt like this. It can feel pretty overwhelming sometimes, but for the most part, I&amp;rsquo;m happy with the progress we&amp;rsquo;ve made and optimistic that we will put on a great event! &lt;/p&gt;
&lt;p&gt;The conference is going to be held in &lt;strong&gt;Accra, Ghana, this year from August 6 to 10&lt;/strong&gt;. We&amp;rsquo;re looking for sponsors, and there&amp;rsquo;s an option for individuals to buy a &lt;strong&gt;sharing ticket&lt;/strong&gt; to sponsor a Pythonista who doesn&amp;rsquo;t have the means to buy their own ticket! You can find out more info on all this on our website: &lt;a href=&quot;https://africa.pycon.org/&quot;&gt;africa.pycon.org&lt;/a&gt;&lt;/p&gt;
&lt;p class=&quot;mt-5&quot;&gt;&lt;strong&gt;Ricky:&lt;/strong&gt; &lt;em&gt;Now for my last questions. What else do you get up to in your spare time? Any other hobbies and interests, aside from Python and coding?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Marlene:&lt;/strong&gt; I really enjoy long walks on the beach, haha. I&amp;rsquo;m joking, but I also genuinely do! I&amp;rsquo;ve been getting into running recently, and I&amp;rsquo;m hoping to try to get myself into good enough form to do a marathon at some point. &lt;/p&gt;
&lt;p&gt;I also really like painting, but not in a cultured, cool way. I sometimes just like to paint and draw as a way to relax. Meditation and gratefulness journaling is also something I like to do each morning, as a good way to start the day. &lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;It was an absolute pleasure speaking to Marlene. If you want to attend PyCon Africa, &lt;a href=&quot;https://africa.pycon.org/register/&quot;&gt;tickets are still available&lt;/a&gt;. If you want to find out more about Marlene, or reach out to her and discuss any of the amazing things she is doing, then you can &lt;a href=&quot;https://twitter.com/marlene_zw&quot;&gt;find her on Twitter&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>OOP Method Types in Python: @classmethod vs @staticmethod vs Instance Methods</title>
      <id>https://realpython.com/courses/python-method-types/</id>
      <link href="https://realpython.com/courses/python-method-types/"/>
      <updated>2019-06-11T14:00:00+00:00</updated>
      <summary>What&#39;s the difference between @classmethod, @staticmethod, and &quot;plain/regular&quot; instance methods in Python? You&#39;ll know the answer after watching this video course.</summary>
      <content type="html">
        &lt;p&gt;What&amp;rsquo;s the difference between &lt;code&gt;@classmethod&lt;/code&gt;, &lt;code&gt;@staticmethod&lt;/code&gt;, and &amp;ldquo;plain/regular&amp;rdquo; instance methods in Python? You&amp;rsquo;ll know the answer after watching this video course:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Regular (instance) methods need a class instance and can access the instance through &lt;code&gt;self&lt;/code&gt;. They can read and modify an objects state freely.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Class methods, marked with the &lt;code&gt;@classmethod&lt;/code&gt; decorator, don&amp;rsquo;t need a class instance. They can&amp;rsquo;t access the instance (self) but they have access to the class itself via &lt;code&gt;cls&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Static methods, marked with the &lt;code&gt;@staticmethod&lt;/code&gt; decorator, don&amp;rsquo;t have access to &lt;code&gt;cls&lt;/code&gt; or &lt;code&gt;self&lt;/code&gt;. They work like regular functions but belong to the class&amp;rsquo;s namespace.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In this course you&amp;rsquo;ll go over the differences between these three kinds of methods in Python. You&amp;rsquo;ll also see when to use each with a simple example, so you can improve your object-oriented programming (OOP) skills in Python.&lt;/p&gt;
&lt;h2 id=&quot;recommended-resources&quot;&gt;Recommended Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://realpython.com/learning-paths/object-oriented-programming-oop-python/&quot;&gt;Learning Path: Object-Oriented Programming (OOP) With Python&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>Introduction to Git and GitHub for Python Developers</title>
      <id>https://realpython.com/courses/python-git-github-intro/</id>
      <link href="https://realpython.com/courses/python-git-github-intro/"/>
      <updated>2019-06-04T14:00:00+00:00</updated>
      <summary>What is Git,  what is GitHub, and what&#39;s the difference? Learn the basics of Git and GitHub from the perspective of a Pythonista in this step-by-step video course.</summary>
      <content type="html">
        &lt;p&gt;What is Git,  what is GitHub, and what&amp;rsquo;s the difference? Learn the basics of Git and GitHub from the perspective of a Pythonista in this step-by-step video course.&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>Continuous Integration With Python</title>
      <id>https://realpython.com/courses/python-continuous-integration/</id>
      <link href="https://realpython.com/courses/python-continuous-integration/"/>
      <updated>2019-05-28T14:00:00+00:00</updated>
      <summary>In this course, you&#39;ll learn the core concepts behind Continuous Integration (CI) and why they are essential for modern software engineering teams. Find out how to how set up Continuous Integration for your Python project to automatically create environments, install dependencies, and run tests.</summary>
      <content type="html">
        &lt;p&gt;In this course, you&amp;rsquo;ll learn the core concepts behind Continuous Integration (CI) and why they are essential for modern software engineering teams. &lt;/p&gt;
&lt;p&gt;Find out how to set up Continuous Integration for your Python project to automatically create environments, install dependencies, and run tests. You&amp;rsquo;ll learn how to work with GitHub, CircleCI, and PyTest.&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>Interactive Data Visualization in Python With Bokeh</title>
      <id>https://realpython.com/courses/interactive-data-visualization-python-bokeh/</id>
      <link href="https://realpython.com/courses/interactive-data-visualization-python-bokeh/"/>
      <updated>2019-05-21T14:00:00+00:00</updated>
      <summary>This course will get you up and running with Bokeh, using examples and a real-world dataset. You&#39;ll learn how to visualize your data, customize and organize your visualizations, and add interactivity.</summary>
      <content type="html">
        &lt;p&gt;Bokeh prides itself on being a library for &lt;em&gt;interactive&lt;/em&gt; data visualization. The graphics are rendered using HTML and JavaScript, and your visualizations are easy to share as an HTML page. You will create a number of visualizations based on a real-world dataset. &lt;/p&gt;
&lt;p&gt;The goal of this course is to get you up and running with Bokeh.&lt;/p&gt;
&lt;p&gt;You will learn how to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Transform your data&lt;/strong&gt; into visualizations&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Customize and organize&lt;/strong&gt; your visualizations&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Add interactivity&lt;/strong&gt; to your visualizations&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>Installing Python on Windows, macOS, and Linux</title>
      <id>https://realpython.com/courses/installing-python-windows-macos-linux/</id>
      <link href="https://realpython.com/courses/installing-python-windows-macos-linux/"/>
      <updated>2019-05-16T14:00:00+00:00</updated>
      <summary>To get started working with Python, you&#39;ll need to have access to the Python interpreter. There are several common ways to accomplish this and in this course, you will learn how to install the latest version of Python on your computer.</summary>
      <content type="html">
        &lt;p&gt;To get started working with Python, you&amp;rsquo;ll need to have access to the Python interpreter. There are several common ways to accomplish this. &lt;/p&gt;
&lt;p&gt;&lt;strong&gt;In this course, you will learn how to install the latest version of Python 3 on your computer.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Many operating systems, such as macOS and Linux, come with Python pre-installed. The version of Python that comes with your operating system is called your &lt;em&gt;system Python&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;The system Python is almost always out-of-date, and may not even be a full Python installation. It&amp;rsquo;s essential that you have the most recent version of Python so that you can follow along successfully with the examples in this book.&lt;/p&gt;
&lt;p&gt;There are two major versions of Python available: Python 2, also known as legacy Python, and Python 3.  Python 2 was released in the year 2000 and will reach its end-of-life &lt;a href=&quot;https://pythonclock.org/&quot;&gt;on January 1, 2020&lt;/a&gt;. This course focuses on Python 3.&lt;/p&gt;
&lt;p&gt;It is split into three sections: Windows, macOS, and Linux. Just find the section for your operating system and follow the steps to get your computer set-up.&lt;/p&gt;
&lt;p&gt;If you have a different operating system, check out the &lt;a href=&quot;https://realpython.com/installing-python/&quot;&gt;Python 3 Installation &amp;amp; Setup Guide&lt;/a&gt; maintained on &lt;a href=&quot;https://realpython.com&quot;&gt;realpython.com&lt;/a&gt; to see if your OS is covered.&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>
